Решил я попробовать работать с UART. Для дальнейшего моего проекта “умный дом” мне необходимо передавать данные между модулями на МК расположенными в разных местах дома по протоколу RS-485. Познакомился с этим протоколом и понял, что лучше всего передавать данные используя UART. В основном данный материал я взял вот с этого сайта.
В качестве отладочной платы с этим микропроцессором я буду использовать STM8L-Discovery, в которой есть свой отладчик ST-Link. Среду для программирования будем использовать IAR.
Запуск UART
И так, наш процессор STM8L152C6 в дефолтной конфигурации тактируется от HSI (High Speed Internal) — высокочастотного внутреннего RC генератора с частотой 16МГц. В STM8L тактирование всех периферийных устройств по умолчанию отключено для снижения энергопотребления. По этому, чтобы работать с UART и его регистрами нам нужно сначала подать на него тактирование.
Для управления делителем системного тактового сигнала используется регистр CLK_CKDIVR:
Мы будем использовать максимальную частоту ядра (16МГц в нашем случае) и устанавливаем 3 последних младших бита в нули:
1 |
CLK_CKDIVR=0x00; //делитель частоты 1 |
Далее нам нужно подать эту частоту на модуль USART чтобы уже начать с ним работать. Управление подачей тактирования на периферию осуществляется регистром CLK_PCKENRx. За включение каждого устройства отвечает отдельный бит:
Как видно из картинки выше, чтобы включить USART1 нужно установить в единицу 5й бит регистра CLK_PCKENR1:
1 |
CLK_PCKENR1_bit.PCKEN15 = 1; |
Перейдем теперь к настройке USART1. Исходя из документации к плате stm8l-discovery узнаем, что ножка PC3 — USART1_TX, а ножка PC2 — USART1_RX. Это значит что ножку PC2 нужно установить на вход, а PC3— на выход:
1 2 |
PC_DDR &= ~(1 << 2); //PC2 RX USART1 receive (вход) PC_DDR|=1<<3; //PC3 TX USART1 transmit (выход) |
Мне не очень понравился выше представленный код. Я написал его проще (на мой взгляд). Если я ошибаюсь прошу более знающих программистов разъяснить почему я не прав.
1 2 |
PC_DDR_bit.DDR2=0; //PC2 RX USART1 receive (вход) PC_DDR_bit.DDR3=1; //PC3 TX USART1 transmit (выход) |
Настройка UART
Произведем настройки регистра USART_CR1:
29.6.5 Control register 1 (USART_CR1)
Address offset: 0x04
Reset value: 0x00
Bit 7 R8: Receive data bit 8
This bit is used to store the 9th bit of the received word when M=1Bit 6 T8: Transmit data bit 8
This bit is used to store the 9th bit of the transmitted word when M=1Bit 5 USARTD: USART disable (for low power consumption)
When this bit is set the USART prescaler and outputs are stopped at the end of the current byte transfer in order to reduce power consumption. This bit is set and cleared by software.
0: USART enabled
1: USART prescaler and outputs disabledBit 4 M: word length
This bit determines the word length. It is set or cleared by software.
0: 1 Start bit, 8 Data bits, ‘n’ STOP bit (n depending on STOP[1:0] bits in the USART_CR3 register)
1: 1 Start bit, 9 Data bits, 1 STOP bit
Note: The M bit must not be modified during a data transfer (both transmission and reception)Bit 3 WAKE: Wakeup method
This bit determines the USART wakeup method, it is set or cleared by software.
0: Idle line
1: Address markBit 2 PCEN: Parity control enable
This bit selects the hardware parity control (generation and detection). When the parity control is enabled, the computed parity is inserted at the MSB position (9th bit if M=1; 8th bit if M=0) and parity is checked on the received data. This bit is set and cleared by software. Once it is set, PCEN is active after the current byte (in reception and in transmission).
0: Parity control disabled
1: Parity control enabledBit 1 PS: Parity selection
This bit selects the odd or even parity when the parity generation/detection is enabled (PCEN bit set). It is set and cleared by software. The parity will be selected after the current byte.
0: Even parity
1: Odd parityBit 0 PIEN: Parity interrupt enable
This bit is set and cleared by software.
0: Parity interrupt disabled
1: Parity interrupt is generated whenever PE=1 in the USART_SR register
Длинна слова в кадре задается битом М (4м битом) регистра USART_CR1 Если он не установлен, то длинна данных будет 8 бит. Если установлен — 9 бит. Установим стандартным режим приема/передачи — 8 бит данных. Бит PCEN включает/выключает режим контроля четности. Количество стоп-битов настраивается в битах 4 и 5 регистра USART_CR3:
29.6.7 Control register 3 (USART_CR3)
Address offset: 0x06
Reset value: 0x00
Bit 7Reserved
Bits 5:4 STOP: STOP bits
These bits are used for programming the STOP bits.
00: 1 STOP bit
01: Reserved
10: 2 STOP bits
11: 1.5 STOP bitsBit 3 CLKEN: Clock enable
This bit allows the user to enable the USART_CK pin.
0: USART_CK pin disabled
1: USART_CK pin enabledBit 2 CPOL: Clock polarity(1)
This bit allows the user to select the polarity of the clock output on the USART_CK pin. It works in
conjunction with the CPHA bit to produce the desired clock/data relationship
0: USART_CK to 0 when idle
1: USART_CK to 1 when idle.Bit 1 CPHA: Clock phase (1)
This bit allows the user to select the phase of the clock output on the USART_CK pin. It works in
conjunction with the CPOL bit to produce the desired clock/data relationship
0: The first clock transition is the first data capture edge
1: The second clock transition is the first data capture edgeBit 0 LBCL: Last bit clock pulse(1)(2)
This bit allows the user to select whether the clock pulse associated with the last data bit transmitted (MSB) has to be output on the USART_CK pin.
0: The clock pulse of the last data bit is not output to the USART_CK pin.
1: The clock pulse of the last data bit is output to the USART_CK pin.
1.These 3 bits (CPOL, CPHA, LBCL) should not be written while the transmitter is enabled.
2.The last bit is the 8th or 9th data bit transmitted depending on the 8 or 9 bit format selected by the M bit in the USART_CR1 register.
1 2 3 4 |
00: 1 стоп бит 01: Зарезервировано 10: 2 стоп бита 11: 1.5 стоп бита (используется в режиме "Smartcard”) |
Скорость обмена (BaudRate) определяется значением регистра делителя частоты тактирования UART, которое не может быть меньше 16 и рассчитывается по формуле:
1 |
Tx/Rx_baud_rate = fSYSCLK / USART_DIV |
Для получения значения этого делителя мы должны тактовую частоту fSYSCLK поделить на желаемую скорость обмена 9600 bps (Tx/Rx_baud_rate). Мы получим нужное нам значение коэффициента деления USART_DIV:
1 |
16000000ГЦ/9600bps=1666,6 (0х0683 в 16-ричной с округлением) |
Два байта значения USART_DIV записываются сначала в регистр USART_BRR2 затем в USART_BRR1.
1 2 |
USART1_BRR2 = 0x03; USART1_BRR1 = 0x68; |
Установка выводов UART в режим TX и RX вместо портов общего назначения осуществляется при помощи регистра USART2_CR2:
Наверное именно из-за
USART2_CR2 регистра нет необходимости настраивать
регистры GPIO CR1 и GPIO CR2
1 2 |
USART1_CR2_bit.REN=1; //прием USART1_CR2_bit.TEN=1; //передача |
29.6.6 Control register 2 (USART_CR2)
Address offset: 0x05
Reset value: 0x00
Bit 7 TIEN: Transmitter interrupt enable
This bit is set and cleared by software.
0: Interrupt is inhibited
1: An USART interrupt is generated whenever TXE=1 in the USART_SR registerBit 6 TCIEN: Transmission complete interrupt enable
This bit is set and cleared by software.
0: Interrupt is inhibited
1: An USART interrupt is generated whenever TC=1 in the USART_SR registerBit 5 RIEN: Receiver interrupt enable
This bit is set and cleared by software.
0: Interrupt is inhibited
1: An USART interrupt is generated whenever OR=1 or RXNE=1 in the USART_SR registerBit 4 ILIEN: IDLE Line interrupt enable
This bit is set and cleared by software.
0: Interrupt is inhibited
1: An USART interrupt is generated whenever IDLE=1 in the USART_SR registerBit 3 TEN: Transmitter enable (1)(2)
This bit enables the transmitter. It is set and cleared by software.
0: Transmitter is disabled
1: Transmitter is enabledBit 2 REN: Receiver enable
This bit enables the receiver. It is set and cleared by software.
0: Receiver is disabled
1: Receiver is enabled and begins searching for a start bitBit 1 RWU: Receiver wakeup(3)(4)
This bit determines if the USART is in mute mode or not. It is set and cleared by software and can be cleared by hardware when a wakeup sequence is recognized.
0: Receiver in active mode
1: Receiver in mute modeBit 0 SBK: Send break
This bit set is used to send break characters. It can be set and cleared by software. It should be set by software, and will be reset by hardware during the STOP bit of break.
0: No break character is transmitted
1: Break character will be transmitted1.During transmission, a “0” pulse on the TEN bit (“0” followed by “1”) sends a preamble (idle line) after the current word.
2.When TEN is set there is a 1 bit-time delay before the transmission starts.
3.Before selecting Mute mode (by setting the RWU bit) the USART must first receive a data byte, otherwise it cannot function in Mute mode with wakeup by Idle line detection.
4.In address mark detection wakeup configuration (WAKE bit=1) the RWU bit cannot be modified by software while the RXNE bit is set.
Режим передачи данных
В этом режиме регистр USART_DR состоит из буфера TDR и сдвиговым регистром передатчика, передающий кадр непосредственно в линию TX. Как только у нас в регистре USART_DR появляются данные, они сразу же перемещаются в буферный регистр TDR, а из него уже в сдвиговый регистр. Флаг TXE устанавливается в регистре USART_SR когда содержание буфера TDR было передано в регистр сдвига и передача началась. Следовательно, буферный регистр TDR пуст и следующие данные могут быть записаны в регистр USART_DR без перезаписи буферного регистра TDR. Это значит, что при попытке записи в регистр USART_DR когда флаг TXE сброшен, буферный регистр не будет пустым (т.к. не закончилась отправка предыдущего байта в сдвиговом регистре), и ожидающий отправки байт в буфере TDR будет перезаписан. Этот флаг генерирует прерывание, если установлен бит TIEN регистра USART1_CR2.
1 2 |
0: Данные не переданы в регистр сдвига 1: Данные переданы в сдвиговый регистр |
Если передача кадра в сдвиговом регистре полностью завершена и флаг TXE установлен (буфер TDR чист), устанавливается флаг TC регистра USART_SR. Это означает полное завершение передачи каких-либо данных по UART. По этому флагу так же есть прерывание, если установлен бит TCIEN регистра USART1_CR2.
1 2 |
0: Передача не завершена 1: Передача завершена |
Для того чтобы передать данные, мы должны ждать, пока буфер TDRосвободится, и флаг TXE регистра USART_SR не будет установлен.
1 2 |
while(!(USART1_SR_bit.TXE)); //Ожидаем освобождения буферного регистра TDR TDRUSART1_DR='F'; // Отправляем символ "F". |
29.6.1 Status register (USART_SR)
Address offset: 0x00
Reset value: 0xC0
Bit 7 TXE: Transmit data register empty
This bit is set by hardware when the content of the TDR register has been transferred into the shift register. An interrupt is generated if the TIEN bit=1 in the USART_CR2 register. It is cleared by a write to the USART_DR register.
0: Data is not transferred to the shift register
1: Data is transferred to the shift registerBit 6 TC: Transmission complete
TC bit is set by hardware if the transmission of a frame containing data is complete and TXE bit is set.
An interrupt is generated if TCIEN=1 in the USART_CR2 register.
TC bit is cleared either by a software sequence (a read to the USART_SR register followed by a write to the USART_DR register), or by programming the bit to ‘0’. This clear sequence is recommended only for multibuffer communications.
0: Transmission is not complete
1: Transmission is completeBit 5 RXNE: Read data register not empty
This bit is set by hardware when the content of the RDR shift register has been transferred to the USART_DR register. An interrupt is generated if RIEN=1 in the USART_CR2 register. It is cleared by a read to the USART_DR register.
0: Data is not received
1: Received data is ready to be read.Bit 4 IDLE: IDLE line detected (1)
This bit is set by hardware when an Idle Line is detected. An interrupt is generated if the ILIEN=1 in the USART_CR2 register. It is cleared by a software sequence (a read to the USART_SR register followed by a read to the USART_DR register).
0: No Idle Line is detected
1: Idle Line is detectedBit 3 OR: Overrun error(2)
This bit is set by hardware when the word currently being received in the shift register is ready to be transferred into the RDR register while RXNE=1. An interrupt is generated if RIEN=1 in the USART_CR2 register. It is cleared by a software sequence (a read to the USART_SR register followed by a read to the USART_DR register).
0: No Overrun error
1: Overrun error is detectedBit 2 NF: Noise flag (3)
This bit is set by hardware when noise is detected on a received frame. It is cleared by a software sequence (a read to the USART_SR register followed by a read to the USART_DR register).
0: No noise is detected
1: Noise is detectedBit 1 FE: Framing error (4)
This bit is set by hardware when a de-synchronization, excessive noise or a break character is detected. It is cleared by a software sequence (a read to the USART_SR register followed by a read to the USART_DR register).
0: No framing error is detected
1: Framing error or break character is detectedBit 0 PE: Parity error
This bit is set by hardware when a parity error occurs in receiver mode. It is cleared by a software sequence (a read to the status register followed by a read to the USART_DR data register). You have to wait for the RXNE flag to be set before clearing it. An interrupt is generated if PIEN=1 in the USART_CR1 register.
0: No parity error
1: Parity error1.The IDLE bit is not set again until the RXNE bit has been set itself (i.e. a new idle line occurs)
2.When this bit is set, the RDR register content is not lost but, the shift register is overwritten.
3.This bit does not generate an interrupt as it appears at the same time as the RXNE bit which itself generates an interrupt.
4.This bit does not generate an interrupt as it appears at the same time as the RXNE bit which itself generates an interrupt. If the word currently being transferred causes both a frame error and an overrun error, it is transferred and only the OR bit is set.
Режим приема данных
Теперь разберемся с приемом. В этом режиме регистр USART_DR состоит из буфера RDR и сдвиговым регистром приемника, читающего данные с ноги RX. Когда данные из сдвигового регистра перемещаются в буферный регистр RDR, устанавливается флаг RXNE регистра USART_SR. Эти данные становятся доступными в регистре USART_DR. Флаг RXNEочищается при попытке чтения регистра USART_DR. Так же генерируется прерывание, если бит RIEN установлен в регистре USART_CR2. Разрешаем это прерывание:
1 2 3 4 5 6 |
USART1_CR2_RIEN=1; //Прерывание по приему #pragma vector=USART_R_OR_vector __interrupt void USART1_RXE(void) { USART1_DR=USART1_DR; //Отправляем тоже, что и приняли (эхо) } |
Пример
Наконец, собираем все вместе. Вот полный код инициализации UART, отправка символа «F» при старте и режим приема «эхо»
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include "iostm8l152c6.h" #include "intrinsics.h" int main() { CLK_CKDIVR=0x00; //делитель частоты 1 CLK_PCKENR1_bit.PCKEN15 = 1; //Подаём тактирование на UASART1 PC_DDR_bit.DDR2=0; //PC2 RX USART1 receive (вход) PC_DDR_bit.DDR3=1; //PC3 TX USART1 transmit (выход) USART1_CR1_bit.M=0; USART1_BRR2 = 0x03; USART1_BRR1 = 0x68; USART1_CR2_bit.REN=1; //прием USART1_CR2_bit.TEN=1; //передача USART1_CR2_RIEN=1; //Прерывание по приему __enable_interrupt (); // Разрешаем прерывания. while(!(USART1_SR_bit.TXE)); //Ожидаем освобождения буферного регистра TDR USART1_DR='F'; // Отправляем символ "F". while (1){} //беск. цикл } #pragma vector=USART_R_OR_vector __interrupt void USART1_RXE(void) { USART1_DR=USART1_DR; //Отправляем тоже, что и приняли (эхо) } |
Пока писал статью появились некоторые сомнения в правильности написанного кода. Предполагаю, что я неправильно его понимаю. Сам код написан и проверен в МК с использованием преобразователя USB to COM. меня смутила вот эта строка взятая с вышеуказанного сайта
Вот полный код инициализации UART, отправка символа «F» при старте и режим приема «эхо»
Я проверил программу следующим образом. Подключил преобразователь USB to COM к выводам PC2 и PC3. Запустил на ПК программу Terminal v1.9b. Цель эксперимента такова: при вводе символа или строки в поле SEND в окне отправки я должен увидеть отправленный символ или строку, а в окне приёма должен так же появится отправленный символ или строка. То есть контроллер должен принять отправленный символ выводом PC2, пропустить эти данные через код программы и выдать отправленный символ обратно в преобразователь USB to COM через вывод PC3. Но судя из описания автора статьи контроллер при старте программы должен отправить символ “F” и принять его.
Видать я немного устал и не могу сообразить как проверить работоспособность UART. У меня есть модуль модема A6. Постараюсь сегодня набросать простой код который заставит модем позвонить на другой телефон. И второй кусок кода должен принять звонок с другого мобильника и засветить светодиод. Это я думаю будет более точная проверка работоспособности UART. О результатах отпишусь в другой статье. Всем спасибо за внимание.