PROGCONT.RU

Форма входа







Регистрация Вход/

Пример Пример Пример


STM8S UART использование в LIN, IrDA, Smartcard и SPI часть2.


LIN режим или локальная сеть применяемая в автомобилях.

 Для тех кому интересно для чего был разработан протокол LIN и как он функционирует прошу почитать данную статью про LIN где подробно и понятно описано. Надеюсь прочитали статью и уяснили что MASTER перед началом обмена информацией с нужным SLAVE обязан сначала отослать команду Break, байт для синхронизации Synch Field, байт заголовок Header и байты данных. Что требуется от Slave дождаться на линии связи команду Break, автоматически синхронизировать свою частоту получая Synch Field, прочитать Header и если посылка для него принять все данные.
 Это основные действия которые контроллер может делать аппаратно а вот формировать Header байт( адрес, количество передаваемых данных и биты целостности) вы должны программно, для обмена информацией между устройствами вы можете применять общепринятые протоколы о которых можно узнать в интернете или придумать новый для своих нужд.
 В STM8S есть четыре UART из которых в UART1 отсутствует устройство синхронизации поэтому его можно применять только как MASTER, остальные UART2-UART4 из за наличия устройства синхронизации по желанию.
 В примере я буду использовать контроллер STM8S207R8 на борту которого имеется UART1 будет главным и UART3 подчиненный, программа работает следующим образом из UART1 в UART3 сначала отправляем команду Break потом Synch Field следом заголовок Header который будет произвольным числом равный 111 и заканчиваем байтом данных 255, если все проедет удачно то вывод контроллера PD0 будет менять свое состояние или мигать подключенный к нему светодиод. Передача данных у меня будет происходить по двум линиям связи или Full duplex для этого я просто соединю соответствующие выводы UART1 и UART3 вместе. Также возможна передача данных по одной линии связи Half duplex в примере <<Подключение с использованием одной линии связи, Half duplex режим.>> посмотрите настройку и изменение направление данных.

#include "stm8s.h"
//Байт для приема Header.
uint8_t recUART3_Header=0;
//Байт для приема данных.
uint8_t recUART3_Data=0;
void pause(uint32_t p){for(uint32_t i=0; i<p; i++){}}
int main( void ){
//Настройка для вывода PD0 контроля или светодиода.
GPIO_Init( GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST);
//Настройка UART1, тут стандартно.
UART1_Init( 9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
//Продолжительность Break 11 бит.
UART1_LINBreakDetectionConfig( UART1_LINBREAKDETECTIONLENGTH_11BITS);
//Включаем прерывание UART1 от приема данных.
UART1_ITConfig( UART1_IT_RXNE_OR, ENABLE);
//Так включаем UART1 в режиме LIN.
UART1_LINCmd( ENABLE);
//Тут тоже стандартно только отсутствует настройка вывода CLOCK у UART3 его нет.
UART3_Init( 9600, UART3_WORDLENGTH_8D, UART3_STOPBITS_1, UART3_PARITY_NO, UART3_MODE_TXRX_ENABLE);
//Дополнительные настройки UART3 будет работать как подчиненный, включаем автонастройку частоты и как будет изменятся делитель.
UART3_LINConfig( UART3_LIN_MODE_SLAVE, UART3_LIN_AUTOSYNC_ENABLE, UART3_LIN_DIVUP_LBRR1);
//Продолжительность Break 11 бит.
UART3_LINBreakDetectionConfig( UART3_LINBREAKDETECTIONLENGTH_11BITS);
//Подключаем прерывание от приема данных.
UART3_ITConfig( UART3_IT_RXNE_OR, ENABLE);
//Подключаем прерывание от возникновения на линии связи Break.
UART3_ITConfig( UART3_IT_LBDF, ENABLE);
//Подключаем прерывание от приема Header.
UART3_ITConfig( UART3_IT_LHDF, ENABLE);
//Включаем UART3.
UART3_LINCmd( ENABLE);
//Включаем все прерывания.
enableInterrupts();

while(1){
//Так отправляется Break, просто установив бит.
UART1_SendBreak();
//Отправляем байт синхронизации.
UART1_SendData8( 0x55);
while(!UART1_GetFlagStatus( UART1_FLAG_TXE));
while(!UART1_GetFlagStatus( UART1_FLAG_TC));
//Отправляем Header.
UART1_SendData8( 111);
while(!UART1_GetFlagStatus( UART1_FLAG_TXE));
while(!UART1_GetFlagStatus( UART1_FLAG_TC));
//Тут отправка байта данных.
UART1_SendData8( 255);
while(!UART1_GetFlagStatus( UART1_FLAG_TXE));
//Не большая пауза и все сначала.
pause(10000);
}
}
//Обработчик прерывания для UART1.
INTERRUPT_HANDLER( UART1_RX_IRQHandler, 18)
{
if(UART1_GetFlagStatus( UART1_FLAG_RXNE)){
//Тут читаем принятые данные.
}
}
//Обработчик прерывания для UART3.
INTERRUPT_HANDLER( UART3_RX_IRQHandler, 21)
{
//Читаем Header.
if( UART3_GetFlagStatus( UART3_FLAG_LHDF)){ recUART3_Header=UART3_ReceiveData8(); UART3_ClearFlag( UART3_FLAG_LHDF);}
//Читаем данные.
if( UART3_GetFlagStatus( UART3_FLAG_RXNE)){ recUART3_Data=UART3_ReceiveData8();}
//На линии Break.
if( UART3_GetFlagStatus( UART3_FLAG_LBDF)){ UART3_ClearFlag( UART3_FLAG_LBDF);}
//Comments.
//Ошибка приема Header.
if( UART3_GetFlagStatus( UART3_FLAG_OR_LHE)){ }
//Тут меняем состояние вывода PD0, если приняли правильно Header и данные.
if( recUART3_Header==111&recUART3_Data==255){ GPIO_WriteReverse( GPIOD, GPIO_PIN_0);}
}

#ifdef USE_FULL_ASSERT
void assert_failed( uint8_t* file, uint32_t line)
{
while (1){}
}
#endif


Режим IrDA или передача информации по инфракрасному порту.

 Для реализации этого метода передачи информации нам потребуется инфракрасный излучатель и приемник, на схеме ниже смотрите как подключить, небольшая подсказка ИК излучатель и передатчик можно взять разобрав щелевой оптический датчик.

нет рисунка

 Передача, прием данных происходит не напрямую а через специальные модули которые изменяют сигналы, смотрите ниже схему и как будет выглядеть передаваемая информация на выводах TX, RX контроллера.

нет рисунка

 Сам IrDA может работать в двух режимах это IRDAMODE_NORMAL( нормальный) и IRDAMODE_LOWPOWER( пониженного потребления), в первом случае продолжительность импульса нуля должно быть 3 части из 16 частей бита(3/16) во втором 3 периода выходящей частоты из PSC( устанавливается функцией UART1_SetPrescaler();) которая не должна быть меньше 1,42MHz и превышать 2,12MHz.

 Передача байтов происходит как с простым UART только принимать или отправлять можно по очереди, наверное для предотвращения искажения сигналов, и конечно ниже примеры отправляющего и принимающего устройства .

#include "stm8s.h"
//Байт для отправки данных.
uint8_t recUART1_Data=0;
void pause(uint32_t p){for(uint32_t i=0; i<p; i++){}}
int main( void ){
//Предделитель HSI равен 1, частота контроллера 16MHz.
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
//Настройка UART1, тут стандартно.
UART1_Init( 9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
//Устанавливаем предделитель IrDA.
UART1_SetPrescaler( 0x1);
//IrDA работает в нормальном режиме 3/16.
UART1_IrDAConfig( UART1_IRDAMODE_NORMAL);
//Включаем UART c IrDA.
UART1_IrDACmd( ENABLE);
while(1){
//Тут отправка байта данных.
uint8_t q=111;
UART1_SendData8( q);
while(!UART1_GetFlagStatus( UART1_FLAG_TXE));
while(!UART1_GetFlagStatus( UART1_FLAG_TC));
pause(100000);
}}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif
#include "stm8s.h"
//Байт для приема данных.
uint8_t recUART1_Data=0;
int main( void ){
//Предделитель HSI равен 1, частота контроллера 16MHz.
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
//Настройка для вывода PD0 контроля или светодиода.
GPIO_Init( GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST);
//Настройка UART1, тут стандартно.
UART1_Init( 9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
//Включаем прерывание от приема данных.
UART1_ITConfig( UART1_IT_RXNE_OR, ENABLE);
//Устанавливаем предделитель IrDA.
UART1_SetPrescaler( 0x1);
//IrDA работает в нормальном режиме 3/16.
UART1_IrDAConfig( UART1_IRDAMODE_NORMAL);
//Включаем UART c IrDA.
UART1_IrDACmd( ENABLE);
enableInterrupts(); while(1){
//Тут ваш код.
}}
//Обработчик прерывания для UART1.
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
if(UART1_GetFlagStatus( UART1_FLAG_RXNE)){
//Читаем принятый байт.
recUART1_Data=UART1_ReceiveData8();
//Тут меняем состояние вывода PD0, если приняли правильно данные.
if( recUART1_Data==111){GPIO_WriteReverse( GPIOD, GPIO_PIN_0);}
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif


Smartcard режим или читаем информацию с чипов банковских и SIM карт.

 Перед началом написания статьи я как многие считал что чип который находится в сим и банковских картах является всего лишь картой памятью для хранения данных, но углубляясь в изучении я понял что ошибался и очень сильно.
 Чип в картах это не большой процессор с флеш памятью для хранения данных причем со своей небольшой операционной системой которая обслуживает все запросы к нему( чтение пин кода, хранение-чтение сообщений, номера телефонов, данные о банковском счете и так далее).
 Углубляться в работу этой системы я не буду, читаем информацию в интернете или просмотрите это:  хорошая статья, скриншот статьи на всякий случай, ISO 7816 на русском.
 Для примера я буду использовать контроллер STM8S207R8 потому что имеет UART1 и UART3, первый я буду использовать для общения с сим картой через второй выведем полученную информацию на монитор, схема подключения ниже с симкой и USB-UART переходником.

нет рисунка

 Сим карте( MTC) которую я использую необходимо питание от 3.3 до 5 вольт, тактовый сигнал CLK( от 1MHz до 5MHz) в нашем случае 4MHz, линия сброса RST у контроллера для этого будет использован вывод PA4 и линия связи I/O. Передача данных происходит асинхронно, скорость зависит от частоты тактирования смарт карты потому что для отправки одного бита данных нужно 372 такта у нас получится 4000000/372=10752 baud rate.
 Теперь небольшой пример в котором после включения контроллера он сразу начинает тактировать сим карту, производит сброс ее, ожидает прихода ATR отклика( первичная информация для обмена данными) у меня выглядит вот так

нет рисунка

 потом ждем небольшое время и отправляем посылку настроек PTS в сим карту после удачного приема она должна переслать PTS обратно в контролер, смотрите ниже как у меня.

нет рисунка

 Сам код программы.

#include "stm8s.h"
void pause(uint32_t p){for(uint32_t i=0; i<p; i++){}}
void main(void)
{
//Настройка вывода для I/O.
GPIO_Init( GPIOA, GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_FAST);
//Настройка вывода для CLK.
GPIO_Init( GPIOA, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST);
//Настройка вывода для RST.
GPIO_Init( GPIOA, GPIO_PIN_4, GPIO_MODE_OUT_PP_LOW_SLOW);
//Тактирование контроллера от HSI частота 16MHz.
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
//Настройка UART1 для сим карты.
UART1_Init( 10752, UART1_WORDLENGTH_9D, UART1_STOPBITS_1_5, UART1_PARITY_EVEN, UART1_SYNCMODE_CLOCK_ENABLE, UART1_MODE_TXRX_ENABLE);
//Делитель для UART1, частота будет 16MHz/4=4MHz.
UART1_SetPrescaler(0x02);
//Guard Time ожидает два байта.
UART1_SetGuardTime(0x2);
//Включаем прерывание от ошибки четности и приема данных.
UART1_ITConfig(UART1_IT_PE, ENABLE);
UART1_ITConfig( UART1_IT_RXNE_OR, ENABLE);
enableInterrupts();
//Включаем ожидание ответа ошибки.
UART1_SmartCardNACKCmd(ENABLE);
//Включаем UART1 в режиме SmartCard.
UART1_SmartCardCmd(ENABLE);
//Настройки для UART3 стандартны только скорость 115200.
UART3_Init( 115200, UART3_WORDLENGTH_8D, UART3_STOPBITS_1, UART3_PARITY_NO, UART3_MODE_TXRX_ENABLE);
UART3_Cmd(ENABLE);
//Сброс сим карты, устанавливаем на RST низкий и после паузы высокий уровень.
pause( 5000);
GPIO_WriteLow(GPIOA, GPIO_PIN_4);
pause( 5000);
GPIO_WriteHigh(GPIOA, GPIO_PIN_4);
//Ожидаем прихода ATR.
pause( 1000000);
//Отключаем прием данных, отправляем PTS-FF,10,94,7B.
UART1->CR2 &= (uint8_t)(~UART1_CR2_REN);
UART1_SendData8( 0xFF);
while(!UART1_GetFlagStatus( UART1_FLAG_TXE));
UART1_SendData8( 0x10);
while(!UART1_GetFlagStatus( UART1_FLAG_TXE));
UART1_SendData8( 0x94);
while(!UART1_GetFlagStatus( UART1_FLAG_TXE));
UART1_SendData8( 0x7B);
while(!UART1_GetFlagStatus( UART1_FLAG_TXE));
while(!UART1_GetFlagStatus( UART1_FLAG_TC));
//Включаем прием данных.
UART1->CR2 |= (uint8_t)UART1_CR2_REN;
while (1)
{
//Ваш код.
}
}
//Обработчик для ошибки четности и приема данных от UART1.
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
if(UART1_GetFlagStatus( UART1_FLAG_PE))
{
//Сброс ошибки.
UART1_ReceiveData8();
}
if(UART1_GetFlagStatus( UART1_FLAG_RXNE))
{
//Отсылаем данные на монитор через UART3.
UART3_SendData8(UART1_ReceiveData8());
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1)
{
}
}
#endif

 Тут показано как происходит обмен данными между сим картой и контроллером, для реализации что то серьезного вам придется изучить более подробно стандарт ISO7816.


Синхронный режим или обмен данными с SPI.

 Я думаю вы уже знаете как работать с SPI если нет читайте эту статью, тут тоже все просто единственное прибавится дополнительный вывод для синхронизации. В примере я буду использовать отладочную плату STM8 Value line discovery с контроллером STM8S903K3, у него имеются UART и SPI просто соединим их вместе как на схеме ниже.

нет рисунка

 Программа работает следующим образом UART1 отправляет в SPI байт 111, в прерывании SPI принимает и проверяет если правильно принял то из прерывания отсылает в UART1 байт 222, если вся цепочка прошла удачно то вывод PD0 будет менять свое состояние или мигать светодиод.

#include "stm8s.h"
uint8_t data;
void pause( uint32_t p){ for( uint32_t i=0; i<p; i++){ }}
int main( void )
{
//Настраиваем вывод для светодиода.
GPIO_Init( GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST);
//Настройка UART1 как SPI MASTER и включения вывода для тактирования.
UART1_Init(9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, (UART1_SyncMode_TypeDef)(UART1_SYNCMODE_CLOCK_ENABLE | UART1_SYNCMODE_CPOL_LOW |UART1_SYNCMODE_CPHA_MIDDLE |UART1_SYNCMODE_LASTBIT_ENABLE), UART1_MODE_TXRX_ENABLE);
//Включаем прерывание UART1 на прием данных.
UART1_ITConfig( UART1_IT_RXNE_OR, ENABLE);
UART1_Cmd( ENABLE);
//Настройка SPI как SLAVE.
SPI_Init(SPI_FIRSTBIT_LSB, SPI_BAUDRATEPRESCALER_2, SPI_MODE_SLAVE, SPI_CLOCKPOLARITY_LOW, SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_2LINES_FULLDUPLEX, SPI_NSS_SOFT, 0x07);
//Включаем прерывание SPI на прием данных.
SPI_ITConfig( SPI_IT_RXNE, ENABLE);
SPI_Cmd( ENABLE);
enableInterrupts();
while(1){
//Отсылаем в SPI 111.
UART1_SendData8(111);
pause(10000);
}
return 0;
}
//Обработчик прерывания UART1.
INTERRUPT_HANDLER( UART1_RX_IRQHandler, 18){
if(UART1_GetFlagStatus( UART1_FLAG_RXNE)){
data=UART1_ReceiveData8();
if( data==222){GPIO_WriteReverse( GPIOD, GPIO_PIN_0);}
}
}
//Обработчик прерывания SPI.
INTERRUPT_HANDLER(SPI_IRQHandler, 10){
if(SPI_GetFlagStatus( SPI_FLAG_RXNE)){
data=SPI_ReceiveData();
if( data==111){ SPI_SendData(222);}
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Не забываем что бы получить данные от SPI SLAVE мы должны его тактировать а это происходит когда ему отсылают данные, поэтому UART1 должен получить данные во время отправки у SPI должны записаны в RX буфер.


Комментариев нет  Только зарегистрированные пользователи могут оставлять комментарии!