STM8S+SDCC+SPL: использование модуля UART1 на примере функции printf()
UART обладает двумя важными преимуществами перед остальными интерфейсами: во-первых, через TTL-конвертер его напрямую можно подключить к компьютеру, а во-вторых, линии связи между двумя узлами могут достигать 50 метров, что позволяет без проблем построить, к примеру, локальную сеть типа SmartHome. В STM8 скорость передачи через UART может достигать 1Mbit/s при частоте системной шины в 16MHz.
Микроконтроллеры STM8S могут обладать несколькими UART модулями,правда характеристики этих модулей немного разнятся:
Использование UART с помощью стандартной периферийной библиотеки(далее SPL), не сложнее, чем в AVR или даже Arduino. Библиотека, в папке Examples содержит готовые примеры использования UART, которые подробно прокомментированы. НО что бы не скатиться до потребительского отношения, бездумно используя чужой код, я предлагаю пошуршать немного мануалами, чтобы понять, чем же все-таки являются USART модули в STM8, и как ими пользоваться максимально эффективно.
Основные возможности UART1 в stm8s103f3:
LIN и CAN это локальные сети созданные для использования в автомобилестроении:
Основные задачи, возлагаемые на LIN консорциумом европейских автомобильных производителей, — объединение автомобильных подсистем и узлов (таких как дверные замки, стеклоочистители, стеклоподъёмники, управление магнитолой и климат-контролем, электролюк и так далее) в единую электронную систему. LIN-протокол утверждён Европейским Автомобильным Консорциумом как дешёвое дополнение к сверхнадёжному протоколу CAN. LIN и CAN дополняют друг друга и позволяют объединить все электронные автомобильные приборы в единую многофункциональную бортовую сеть. Причём область применения CAN — участки, где требуется сверхнадёжность и скорость; область же применения LIN — объединение дешёвых узлов, работающих с малыми скоростями передачи информации на коротких дистанциях и сохраняющих при этом универсальность, многофункциональность, а также простоту разработки и отладки.
Так же имеется поддержка IrDA
Сам порт IrDA основан на архитектуре коммуникационного СОМ-порта ПК, который использует универсальный асинхронный приемо-передатчик UART и работает со скоростью передачи данных 2400–115200 bps. Связь в IrDA полудуплексная, т.к. передаваемый ИК-луч неизбежно засвечивает соседний PIN-диодный усилитель приемника. Воздушный промежуток между устройствами позволяет принять ИК-энергию только от одного источника в данный момент.
Кроме этого имеется еще Smartcard
Интерфейс является синхронным режимом USART-драйвера, это значит, что передачу каждого бита информации мы синхронизируем частотой на выводе CLK, но здесь есть одно важное отличие от прочих синхронных интерфейсов (вроде того же SPI): для тактирования одного бита информации нужен не один импульс на CLK, а 372 импульса (это магическое число прописано в 3 части ISO7816, и носит название ETU (Elementary Time Unit)), т.е., один бит данных тактируется каждым 372-м (в идеальном случае) фронтом. Сама частота должна лежать в пределах от 1 до 5 МГц.
Как видно, вариантов использования UART много, но сейчас нас будет интересовать классический UART протокол: 8N1.
Регистры модуля UART1 в SPL описываются следующей структурой:
typedef struct UART1_struct { __IO uint8_t SR; /*!< UART1 status register */ __IO uint8_t DR; /*!< UART1 data register */ __IO uint8_t BRR1; /*!< UART1 baud rate register */ __IO uint8_t BRR2; /*!< UART1 DIV mantissa[11:8] SCIDIV fraction */ __IO uint8_t CR1; /*!< UART1 control register 1 */ __IO uint8_t CR2; /*!< UART1 control register 2 */ __IO uint8_t CR3; /*!< UART1 control register 3 */ __IO uint8_t CR4; /*!< UART1 control register 4 */ __IO uint8_t CR5; /*!< UART1 control register 5 */ __IO uint8_t GTR; /*!< UART1 guard time register */ __IO uint8_t PSCR; /*!< UART1 prescaler register */ } UART1_TypeDef;
DR - регистр данных, BRRx - определяют скорость интерфейса, SR - флаговые/статусные регистры, CRх - управляющие режимами работы UART регистры, PSCR - позволяет понизить тактовую частоту UART модуля. Если к примеру, скорость передачи 9600 bod, то незачем модуль гонять вхолостую, можно поставить делитель на 64. GTR - Guard Time Register используется в Smartcard, задает величину защищенного интервала в тактах системной шины тактирования.
Функцией UART1_DeInit(), в регистры записываются следующие значения по умолчанию:
#define UART1_SR_RESET_VALUE ((uint8_t)0xC0) #define UART1_BRR1_RESET_VALUE ((uint8_t)0x00) #define UART1_BRR2_RESET_VALUE ((uint8_t)0x00) #define UART1_CR1_RESET_VALUE ((uint8_t)0x00) #define UART1_CR2_RESET_VALUE ((uint8_t)0x00) #define UART1_CR3_RESET_VALUE ((uint8_t)0x00) #define UART1_CR4_RESET_VALUE ((uint8_t)0x00) #define UART1_CR5_RESET_VALUE ((uint8_t)0x00) #define UART1_GTR_RESET_VALUE ((uint8_t)0x00) #define UART1_PSCR_RESET_VALUE ((uint8_t)0x00)
Функционал модуля UART1 реализуется следующими функциями:
void UART1_DeInit(void); void UART1_Init(uint32_t BaudRate, UART1_WordLength_TypeDef WordLength, UART1_StopBits_TypeDef StopBits, UART1_Parity_TypeDef Parity, UART1_SyncMode_TypeDef SyncMode, UART1_Mode_TypeDef Mode); void UART1_Cmd(FunctionalState NewState); void UART1_ITConfig(UART1_IT_TypeDef UART1_IT, FunctionalState NewState); void UART1_HalfDuplexCmd(FunctionalState NewState); void UART1_IrDAConfig(UART1_IrDAMode_TypeDef UART1_IrDAMode); void UART1_IrDACmd(FunctionalState NewState); void UART1_LINBreakDetectionConfig(UART1_LINBreakDetectionLength_TypeDef UART1_LINBreakDetectionLength); void UART1_LINCmd(FunctionalState NewState); void UART1_SmartCardCmd(FunctionalState NewState); void UART1_SmartCardNACKCmd(FunctionalState NewState); void UART1_WakeUpConfig(UART1_WakeUp_TypeDef UART1_WakeUp); void UART1_ReceiverWakeUpCmd(FunctionalState NewState); uint8_t UART1_ReceiveData8(void); uint16_t UART1_ReceiveData9(void); void UART1_SendData8(uint8_t Data); void UART1_SendData9(uint16_t Data); void UART1_SendBreak(void); void UART1_SetAddress(uint8_t UART1_Address); void UART1_SetGuardTime(uint8_t UART1_GuardTime); void UART1_SetPrescaler(uint8_t UART1_Prescaler); FlagStatus UART1_GetFlagStatus(UART1_Flag_TypeDef UART1_FLAG); void UART1_ClearFlag(UART1_Flag_TypeDef UART1_FLAG); ITStatus UART1_GetITStatus(UART1_IT_TypeDef UART1_IT); void UART1_ClearITPendingBit(UART1_IT_TypeDef UART1_IT);
Пример программы для пересылки данных с микроконтроллера на компьютер через UART:
#include "stm8s.h" #include "stm8s_gpio.h" #include "stm8s_clk.h" #include "stm8s_tim4.h" #include "stm8s_uart1.h" #include "stdio.h" #define LED_PORT GPIOB #define LED GPIO_PIN_5 #define TIM4_PERIOD 124 #define PUTCHAR_PROTOTYPE void putchar (char c) ErrorStatus status = FALSE; volatile uint16_t count; uint16_t i; INTERRUPT_HANDLER(IRQ_Handler_TIM4, 23) { if (count) count--; TIM4_ClearITPendingBit(TIM4_IT_UPDATE); } void delay_ms(uint16_t ms) { TIM4_Cmd(DISABLE); // stop TIM4_TimeBaseInit(TIM4_PRESCALER_128, TIM4_PERIOD); TIM4_ClearFlag(TIM4_FLAG_UPDATE); TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); count = ms; TIM4_Cmd(ENABLE); // let's go while(count); } int main( void ) { // ----------- GPIO CONFIG ------------------- GPIO_DeInit(LED_PORT); GPIO_Init(LED_PORT, LED, GPIO_MODE_OUT_PP_LOW_FAST); // ---------- CLK CONFIG ----------------------- CLK_DeInit(); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1); // set 16 MHz for CPU TIM4_DeInit(); // uncomment if use HSE on Quartz //status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, // CLK_CURRENTCLOCKSTATE_DISABLE); // ------------ UART1 ------------------- UART1_DeInit(); // 8N1 UART1_Init((uint32_t)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE); enableInterrupts(); i=0; for(;;) { GPIO_WriteReverse(LED_PORT, LED); delay_ms(1000); printf("count: %u\n",++i); } } PUTCHAR_PROTOTYPE { // Write a character to the UART1 UART1_SendData8(c); // Loop until the end of transmission while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET); }
Так же как в AVR, для использования функции printf() нужно только задать функцию putchar(char c), после чего системная библиотека сделает все за вас. Кстати, прошивка вместе с printf(), начинает весить уже от 5 Kбайт.
Результат работы выглядит как-то так:
я предлагаю заглянуть в код функции UART1_SendData8(c):
void UART1_SendData8(uint8_t Data) { /* Transmit Data */ UART1->DR = Data; }
а так же UART1_GetFlagStatus(UART1_FLAG_TXE):
FlagStatus UART1_GetFlagStatus(UART1_Flag_TypeDef UART1_FLAG) { FlagStatus status = RESET; /* Check parameters */ assert_param(IS_UART1_FLAG_OK(UART1_FLAG)); /* Check the status of the specified UART1 flag*/ if (UART1_FLAG == UART1_FLAG_LBDF) { if ((UART1->CR4 & (uint8_t)UART1_FLAG) != (uint8_t)0x00) { /* UART1_FLAG is set*/ status = SET; } else { /* UART1_FLAG is reset*/ status = RESET; } } else if (UART1_FLAG == UART1_FLAG_SBK) { if ((UART1->CR2 & (uint8_t)UART1_FLAG) != (uint8_t)0x00) { /* UART1_FLAG is set*/ status = SET; } else { /* UART1_FLAG is reset*/ status = RESET; } } else { if ((UART1->SR & (uint8_t)UART1_FLAG) != (uint8_t)0x00) { /* UART1_FLAG is set*/ status = SET; } else { /* UART1_FLAG is reset*/ status = RESET; } } /* Return the UART1_FLAG status*/ return status; }
но самая интересная функция, это конечно UART1_Init():
void UART1_Init(uint32_t BaudRate, UART1_WordLength_TypeDef WordLength, UART1_StopBits_TypeDef StopBits, UART1_Parity_TypeDef Parity, UART1_SyncMode_TypeDef SyncMode, UART1_Mode_TypeDef Mode) { uint32_t BaudRate_Mantissa = 0, BaudRate_Mantissa100 = 0; /* Check the parameters */ assert_param(IS_UART1_BAUDRATE_OK(BaudRate)); assert_param(IS_UART1_WORDLENGTH_OK(WordLength)); assert_param(IS_UART1_STOPBITS_OK(StopBits)); assert_param(IS_UART1_PARITY_OK(Parity)); assert_param(IS_UART1_MODE_OK((uint8_t)Mode)); assert_param(IS_UART1_SYNCMODE_OK((uint8_t)SyncMode)); /* Clear the word length bit */ UART1->CR1 &= (uint8_t)(~UART1_CR1_M); /* Set the word length bit according to UART1_WordLength value */ UART1->CR1 |= (uint8_t)WordLength; /* Clear the STOP bits */ UART1->CR3 &= (uint8_t)(~UART1_CR3_STOP); /* Set the STOP bits number according to UART1_StopBits value */ UART1->CR3 |= (uint8_t)StopBits; /* Clear the Parity Control bit */ UART1->CR1 &= (uint8_t)(~(UART1_CR1_PCEN | UART1_CR1_PS )); /* Set the Parity Control bit to UART1_Parity value */ UART1->CR1 |= (uint8_t)Parity; /* Clear the LSB mantissa of UART1DIV */ UART1->BRR1 &= (uint8_t)(~UART1_BRR1_DIVM); /* Clear the MSB mantissa of UART1DIV */ UART1->BRR2 &= (uint8_t)(~UART1_BRR2_DIVM); /* Clear the Fraction bits of UART1DIV */ UART1->BRR2 &= (uint8_t)(~UART1_BRR2_DIVF); /* Set the UART1 BaudRates in BRR1 and BRR2 registers according to UART1_BaudRate value */ BaudRate_Mantissa = ((uint32_t)CLK_GetClockFreq() / (BaudRate << 4)); BaudRate_Mantissa100 = (((uint32_t)CLK_GetClockFreq() * 100) / (BaudRate << 4)); /* Set the fraction of UART1DIV */ UART1->BRR2 |= (uint8_t)((uint8_t)(((BaudRate_Mantissa100 - (BaudRate_Mantissa * 100)) << 4) / 100) & (uint8_t)0x0F); /* Set the MSB mantissa of UART1DIV */ UART1->BRR2 |= (uint8_t)((BaudRate_Mantissa >> 4) & (uint8_t)0xF0); /* Set the LSB mantissa of UART1DIV */ UART1->BRR1 |= (uint8_t)BaudRate_Mantissa; /* Disable the Transmitter and Receiver before setting the LBCL, CPOL and CPHA bits */ UART1->CR2 &= (uint8_t)~(UART1_CR2_TEN | UART1_CR2_REN); /* Clear the Clock Polarity, lock Phase, Last Bit Clock pulse */ UART1->CR3 &= (uint8_t)~(UART1_CR3_CPOL | UART1_CR3_CPHA | UART1_CR3_LBCL); /* Set the Clock Polarity, lock Phase, Last Bit Clock pulse */ UART1->CR3 |= (uint8_t)((uint8_t)SyncMode & (uint8_t)(UART1_CR3_CPOL | UART1_CR3_CPHA | UART1_CR3_LBCL)); if ((uint8_t)(Mode & UART1_MODE_TX_ENABLE)) { /* Set the Transmitter Enable bit */ UART1->CR2 |= (uint8_t)UART1_CR2_TEN; } else { /* Clear the Transmitter Disable bit */ UART1->CR2 &= (uint8_t)(~UART1_CR2_TEN); } if ((uint8_t)(Mode & UART1_MODE_RX_ENABLE)) { /* Set the Receiver Enable bit */ UART1->CR2 |= (uint8_t)UART1_CR2_REN; } else { /* Clear the Receiver Disable bit */ UART1->CR2 &= (uint8_t)(~UART1_CR2_REN); } /* Set the Clock Enable bit, lock Polarity, lock Phase and Last Bit Clock pulse bits according to UART1_Mode value */ if ((uint8_t)(SyncMode & UART1_SYNCMODE_CLOCK_DISABLE)) { /* Clear the Clock Enable bit */ UART1->CR3 &= (uint8_t)(~UART1_CR3_CKEN); } else { UART1->CR3 |= (uint8_t)((uint8_t)SyncMode & UART1_CR3_CKEN); } }
И здесь кроется довольно массивный "подводный камень". Дело в следущем. Как помнится, в AVR была хитрая формула для преобразования скорости передачи в значение регистра UBRR. В STM8 имеется не менее хитрая формула для регистров BRRx:
своя табличка тоже наличествует:
Как не трудно заметить, функция прямо пропорциональна fMASTER. Значение fMASTER UART1_Init() берет из модуля CLK с помощью функции CLK_GetClock():
BaudRate_Mantissa = ((uint32_t)CLK_GetClockFreq() / (BaudRate << 4)); BaudRate_Mantissa100 = (((uint32_t)CLK_GetClockFreq() * 100) / (BaudRate << 4));
А сама CLK_GetClock() выглядит так:
uint32_t CLK_GetClockFreq(void) { uint32_t clockfrequency = 0; CLK_Source_TypeDef clocksource = CLK_SOURCE_HSI; uint8_t tmp = 0, presc = 0; // Get CLK source. clocksource = (CLK_Source_TypeDef)CLK->CMSR; if (clocksource == CLK_SOURCE_HSI) { tmp = (uint8_t)(CLK->CKDIVR & CLK_CKDIVR_HSIDIV); tmp = (uint8_t)(tmp >> 3); presc = HSIDivFactor[tmp]; clockfrequency = HSI_VALUE / presc; } else if ( clocksource == CLK_SOURCE_LSI) { clockfrequency = LSI_VALUE; } else { clockfrequency = HSE_VALUE; } return((uint32_t)clockfrequency); }
Так вот. Если чип будет использовать внешний резонатор HSE, значение частоты резонатора будет браться из именованной константы HSE_VALUE в stm8s.h:
#if !defined HSE_Value #if defined (STM8S208) || defined (STM8S207) || defined (STM8S007) || defined (STM8AF52Ax) || \ defined (STM8AF62Ax) || defined (STM8AF622x) #define HSE_VALUE ((uint32_t)24000000) /* Value of the External oscillator in Hz*/ #else #define HSE_VALUE ((uint32_t)16000000) /* Value of the External oscillator in Hz*/ #endif /* STM8S208 || STM8S207 || STM8S007 || STM8AF62Ax || STM8AF52Ax || STM8AF622x */ #endif /* HSE_Value */
.т.е. если ваш кварц не на 16 МГц, и вы не вписали частоту кварца во время компиляции, или не поправили заголовочный файл stm8s.h, то работать корректно ваш модуль UART не будет. Такой вот тест на внимательность.
Разобравшись c BRRx, осталось пробежаться по управляющим регистрам UART1_CRx. Общая карта регистров для модуля UART1 в STM8S выглядит так:
UART1_Init() для конфигурации UART1 использует регистры: CR1, CR2, CR3.
В CR1 у нас устанвливается длина фрейма равной восьми(установкой бита 4 M), а также сбрасывается аппаратный контроль четности( биты 2 PCEN и бит 1 PS) . Для ясности напомню формат UART кадра:
- Остальные биты:
- Биты 7 и 6 отвечают за передачу кадром 9 бит. Если не ошибаюсь, такое используется в Multi-Processor communication когда локальную сеть строят на одном UART модуле. Тогда несколько бит используются для адресации устройства. Подробнее об этом можно почитать здесь: "Время говорить с камнями или USART Multi-processor Communication Mode" , сам я с этой штукой ни разу не сталкивался.
- Бит 5 отключает тактирование от UART, в целях энергосбережения.
- Бит 3 WAKE - определяет способ пробуждения из энергосберегающего режима. 0 - по освобожлению линии, 1 - по принятию адреса.
- Бит 0 PIEN - разрешает/запрещает прерывание по четности. Прерывание генерируется когда устанавливается флаг PE в регистре UART1_SR.
Кстати, про прерывания. Прерывания UART могут вызывать следующие события:
Полезно будет эту табличку запомнить на будущее. А пока рассмотрим регистр UART_CR2:
Здесь нас интересуют биты 3 TEN и 2 REN, разрешение передачи и приема соответственно. В принципе, т.к. микроконтроллер работает только на передачу, можно было выставить только TEN, тогда пин Rx можно было бы использовать в других задачах.
Биты с седьмого по четвертый устанавливают источник вызова прерывания.
Бит RWU, определяет находится ли UART в "спящем" режиме или в активном. Как я понял из описания, UART можно вывести из режима сна, передачей специальной последовательности.
SBK - этот бит используется для отправки разрывающего стоп-бита. Устанавливается программно, сбрасывается аппаратно.
Регистр UARTx_CR3:
Здесь нас интересуют STOP биты 5:6, которые определяют количество стоп-битов: одни, два или полтора;
LINEN включает LIN режим;
- Остальные биты настраивают вывод синхронизирующего тактового сигнала SCLK pin для работы USART в синхронном режиме.
- CLKEN включает выдачу тактового сигнала для SCLK pin.
- CPOL задает полярность SCLK pin;
- CPHA задет фазу SCLK pin. Передача бита данных будет синхронизирована по первому фронту или по второму;
- LBCL задет вывод последнего бита данных на SCLK pin. Т.к. USART передает фрейм младшим битом вперед, то последним битом будет соответственно старший 8-й или 9-й бит данных, в зависимости от формата фрейма.
Использование USART1 в чипе STM8L051F3 (добавлено 31 августа 2016г.)
В L-серии UART модули лишены LIN и CAN интерфейсов, в остальном же соответствуют USART модулям в STM8S.
Струтура писывающая модуль USART в SPL идентична структуре в S-серии, за тем исключением, что она общаяя для всех модулей:
typedef struct USART_struct { __IO uint8_t SR; /*!< USART status register */ __IO uint8_t DR; /*!< USART data register */ __IO uint8_t BRR1; /*!< USART baud rate register */ __IO uint8_t BRR2; /*!< USART DIV mantissa[11:8] SCIDIV fraction */ __IO uint8_t CR1; /*!< USART control register 1 */ __IO uint8_t CR2; /*!< USART control register 2 */ __IO uint8_t CR3; /*!< USART control register 3 */ __IO uint8_t CR4; /*!< USART control register 4 */ __IO uint8_t CR5; /*!< USART control register 5 */ __IO uint8_t GTR; /*!< USART guard time register */ __IO uint8_t PSCR; /*!< USART prescaler register */ } USART_TypeDef;
Поэтому во всех функциях SPL имеется дополнительный параметр: USART_TypeDef* USARTx - номер модуля USART:
/* Function used to set the USART configuration to the default reset state ***/ void USART_DeInit(USART_TypeDef* USARTx); /* Initialization and Configuration functions *********************************/ void USART_Init(USART_TypeDef* USARTx, uint32_t BaudRate, USART_WordLength_TypeDef USART_WordLength, USART_StopBits_TypeDef USART_StopBits, USART_Parity_TypeDef USART_Parity, USART_Mode_TypeDef USART_Mode); void USART_ClockInit(USART_TypeDef* USARTx, USART_Clock_TypeDef USART_Clock, USART_CPOL_TypeDef USART_CPOL, USART_CPHA_TypeDef USART_CPHA, USART_LastBit_TypeDef USART_LastBit); void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState); void USART_SetPrescaler(USART_TypeDef* USARTx, uint8_t USART_Prescaler); void USART_SendBreak(USART_TypeDef* USARTx); /* Data transfers functions ***************************************************/ void USART_SendData8(USART_TypeDef* USARTx, uint8_t Data); void USART_SendData9(USART_TypeDef* USARTx, uint16_t Data); uint8_t USART_ReceiveData8(USART_TypeDef* USARTx); uint16_t USART_ReceiveData9(USART_TypeDef* USARTx); /* Multi-Processor Communication functions ************************************/ void USART_WakeUpConfig(USART_TypeDef* USARTx, USART_WakeUp_TypeDef USART_WakeUp); void USART_ReceiverWakeUpCmd(USART_TypeDef* USARTx, FunctionalState NewState); void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address); /* Half-duplex mode function **************************************************/ void USART_HalfDuplexCmd(USART_TypeDef* USARTx, FunctionalState NewState); /* Smartcard mode functions ***************************************************/ void USART_SmartCardCmd(USART_TypeDef* USARTx, FunctionalState NewState); void USART_SmartCardNACKCmd(USART_TypeDef* USARTx, FunctionalState NewState); void USART_SetGuardTime(USART_TypeDef* USARTx, uint8_t USART_GuardTime); /* IrDA mode functions ********************************************************/ void USART_IrDAConfig(USART_TypeDef* USARTx, USART_IrDAMode_TypeDef USART_IrDAMode); void USART_IrDACmd(USART_TypeDef* USARTx, FunctionalState NewState); /* DMA transfers management functions *****************************************/ void USART_DMACmd(USART_TypeDef* USARTx, USART_DMAReq_TypeDef USART_DMAReq, FunctionalState NewState); /* Interrupts and flags management functions **********************************/ void USART_ITConfig(USART_TypeDef* USARTx, USART_IT_TypeDef USART_IT, FunctionalState NewState); FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, USART_FLAG_TypeDef USART_FLAG); void USART_ClearFlag(USART_TypeDef* USARTx, USART_FLAG_TypeDef USART_FLAG); ITStatus USART_GetITStatus(USART_TypeDef* USARTx, USART_IT_TypeDef USART_IT); void USART_ClearITPendingBit(USART_TypeDef* USARTx);//, USART_IT_TypeDef USART_IT);
Пример использования printf() для STM8L051F3 выглядит следующим образом:
#include "stm8l.h" #include "stm8l_gpio.h" #include "stm8l_clk.h" #include "stm8l_tim4.h" #include "stm8l_usart.h" #include "stdio.h" #define PORT GPIOB #define LED GPIO_Pin_1 #define TIM4_PERIOD 124 #define PUTCHAR_PROTOTYPE void putchar (char c) volatile uint16_t count; uint8_t i; INTERRUPT_HANDLER(IRQ_Handler_TIM4, 25) { if (count) count--; TIM4_ClearITPendingBit(TIM4_IT_Update); } void delay_ms(uint16_t ms) { TIM4_Cmd(DISABLE); // stop TIM4_TimeBaseInit(TIM4_Prescaler_128, TIM4_PERIOD); TIM4_ClearFlag(TIM4_FLAG_Update); TIM4_ITConfig(TIM4_IT_Update, ENABLE); count = ms; TIM4_Cmd(ENABLE); // let's go while(count); } int main( void ) { // --------- GPIO Config --------------------------- GPIO_DeInit(PORT); GPIO_Init(PORT, LED, GPIO_Mode_Out_PP_Low_Fast); // ---------- CLK Config ----------------------- CLK_DeInit(); CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1); CLK_PeripheralClockConfig(CLK_Peripheral_TIM4, ENABLE); CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE); // ---------- TIM4 Init ----------------------------- TIM4_DeInit(); // ---------- USART Init --------------------------- USART_DeInit(USART1); USART_Init(USART1, (uint32_t)9600, USART_WordLength_8b, USART_StopBits_1, USART_Parity_No, (USART_Mode_TypeDef)(USART_Mode_Tx | USART_Mode_Rx)); enableInterrupts(); i=0; for(;;) { delay_ms(1000); GPIO_ToggleBits(PORT, LED); printf("count: %d\n",++i); } } PUTCHAR_PROTOTYPE { /* Write a character to the USART */ USART_SendData8(USART1, c); /* Loop until the end of transmission */ while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // return (c); }
Здесь ножка PC5 подключается к RX-пину TTL-конвертера, земля микросхемы подключается к земле конвертера. И желательно что бы конвертер питался ыот напряжения 3.3 Вольт.
Результат работы выглядит аналогично примеру для S-серии.
Скачать архив с полными исходниками можно здесь: скачать
Обратная связь
Интересуют вопросы реализации алгоритмов, программирования, выбора электроники и прочая информация, постараюсь осветить в отдельных статьях
пишите мне на netdm@mail.ru
Добавить комментарий