В микроконтроллерах STM32 имеется не менее одного USART порта. Главное отличие их в том, что только USART1 подключен к высокоскоростной шине APB2. Все остальные USART подключены к APB1. Для использования USART в STM32 необходимо прежде всего
- Включить тактиованте шины для USART1
- Настроить выводы RX / TX для USART1
- Установите скорость передачи данных для USART1
- Включить USART1 и его RX-и TX-компонент
Подключаем к проекту файл с именами системных регистров для STM32F1xx это
#include "stm32f10x.h
void UART_init(void)
{
// USART3 init
RCC->APB1ENR |= RCC_APB1ENR_USART3EN; // такты на USART3
GPIOB->CRH &= (~(GPIO_CRH_CNF10_0)); //Настройка порта передатчика
GPIOB->CRH |= (GPIO_CRH_MODE10 | GPIO_CRH_CNF10_1); // AF Push-Pull out (TX)
// GPIOB->CRH &= (~(GPIO_CRH_CNF11)); // Настройка порта приемника
// GPIOB->CRH &= (~(GPIO_CRH_MODE11));
// GPIOB->CRH |= (GPIO_CRH_CNF11_1);
// GPIOB->BSRR |= GPIO_ODR_ODR11; // Input Pull-up (RX)
USART3->CR1 |= USART_CR1_UE; // Разрешить USART3
USART3->BRR = 0x0271; // 57600 baud
USART3->CR1 |= USART_CR1_TE; //Разрешить передатчик
}
Передача байта:
while ((USART3->SR & USART_SR_TXE) != USART_SR_TXE);
USART3->DR = 'D';
void UART_init(void)
{
// USART3 init
RCC->APB1ENR |= RCC_APB1ENR_USART3EN; // такты на USART3
GPIOB->CRH &= (~(GPIO_CRH_CNF10_0)); //Настройка порта передатчика
GPIOB->CRH |= (GPIO_CRH_MODE10 | GPIO_CRH_CNF10_1); // AF Push-Pull out (TX)
// GPIOB->CRH &= (~(GPIO_CRH_CNF11)); // Настройка порта приемника
// GPIOB->CRH &= (~(GPIO_CRH_MODE11));
// GPIOB->CRH |= (GPIO_CRH_CNF11_1);
// GPIOB->BSRR |= GPIO_ODR_ODR11; // Input Pull-up (RX)
USART3->CR1 |= USART_CR1_UE; // Разрешить USART3
USART3->BRR = 0x0271; // 57600 baud
USART3->CR1 |= USART_CR1_TE; //Разрешить передатчик
}
Передача байта:
while ((USART3->SR & USART_SR_TXE) != USART_SR_TXE);
USART3->DR = 'D';
Перед началом работы с USART нужно включить ножки GPIO на вход и на выход:
USART1: PA9/TxD + PA10/RxD
USART2: PA2/TxD + PA3/RxD
USART3: PB10/TxD + PB11/RxD
В случае, если все стандартные контакты USART уже заняты, можно перенаправить их на другие — это называется ремаппинг. USART1 в таком случае переходит на PB6/TxD + PB7/RxD, а USART3 — на PC10/TxD + PC11/RxD. USART2 нельзя ремапнуть на другие пины.
Код изменяется совсем немного: всё, что нужно сделать — это добавить строку AFIO->MAPR |= AFIO_MAPR_USART1_REMAP; и конечно переписать код включения портов ввода-вывода на новые пины:
RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
AFIO->MAPR |= AFIO_MAPR_USART1_REMAP;
GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6_0 | GPIO_CRL_CNF7_0;
int main(void)
{
// Настраиваем ножку PC8 в режим выхода на светодиод на плате
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// Включаем модули USART1 и GPIOA, а также включаем альтернативные функции выходов
RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
// Контакт PA9 будет выходом с альтернативной функцией, а контакт PA10 - входом
GPIOA->CRH &= !GPIO_CRH_CNF9;
GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_0 | GPIO_CRH_CNF10_0;
// Настраиваем регистр тактирования, скорость составит 9600 бод (при тактовой частоте 24 МГц)
USART1->BRR = 0x9C4;
// Выключаем TxD и RxD USART
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;
// Запускаем модуль USART
USART1->CR1 |= USART_CR1_UE;
// Разрешаем прерывание по приёму информации с RxD
USART1->CR1 |= USART_CR1_RXNEIE;
// Назначаем обработчик для всех прерываний от USART1
NVIC_EnableIRQ(USART1_IRQn);
USART1_Send_String("Start\r\n");
// Бесконечный цикл
while(1);
}
void USART1_Send(char chr) {
while(!(USART1->SR & USART_SR_TC));
USART1->DR = chr;
}
void USART1_Send_String(char* str) {
int i=0;
while(str[i])
USART1_Send(str[i++]);
}
// Обработчик всех прерываний от USART1
void USART1_IRQHandler(void) {
// Выясняем, какое именно событие вызвало прерывание. Если это приём байта в RxD - обрабатываем.
if (USART1->SR & USART_SR_RXNE) {
// Сбрасываем флаг прерывания
USART1->SR&=~USART_SR_RXNE;
// Получаем принятый байт
if(USART1->DR=='1') {
GPIO_SetBits(GPIOC, GPIO_Pin_9);
// Отправляем обратно строку "On" с переводом строки
USART1_Send_String("On\r\n");
}
if(USART1->DR=='2') {
GPIO_ResetBits(GPIOC, GPIO_Pin_9);
USART1_Send_String("Off\r\n");
}
}
}
USART1: PA9/TxD + PA10/RxD
USART2: PA2/TxD + PA3/RxD
USART3: PB10/TxD + PB11/RxD
В случае, если все стандартные контакты USART уже заняты, можно перенаправить их на другие — это называется ремаппинг. USART1 в таком случае переходит на PB6/TxD + PB7/RxD, а USART3 — на PC10/TxD + PC11/RxD. USART2 нельзя ремапнуть на другие пины.
Код изменяется совсем немного: всё, что нужно сделать — это добавить строку AFIO->MAPR |= AFIO_MAPR_USART1_REMAP; и конечно переписать код включения портов ввода-вывода на новые пины:
RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
AFIO->MAPR |= AFIO_MAPR_USART1_REMAP;
GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6_0 | GPIO_CRL_CNF7_0;
int main(void)
{
// Настраиваем ножку PC8 в режим выхода на светодиод на плате
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// Включаем модули USART1 и GPIOA, а также включаем альтернативные функции выходов
RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
// Контакт PA9 будет выходом с альтернативной функцией, а контакт PA10 - входом
GPIOA->CRH &= !GPIO_CRH_CNF9;
GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_0 | GPIO_CRH_CNF10_0;
// Настраиваем регистр тактирования, скорость составит 9600 бод (при тактовой частоте 24 МГц)
USART1->BRR = 0x9C4;
// Выключаем TxD и RxD USART
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;
// Запускаем модуль USART
USART1->CR1 |= USART_CR1_UE;
// Разрешаем прерывание по приёму информации с RxD
USART1->CR1 |= USART_CR1_RXNEIE;
// Назначаем обработчик для всех прерываний от USART1
NVIC_EnableIRQ(USART1_IRQn);
USART1_Send_String("Start\r\n");
// Бесконечный цикл
while(1);
}
void USART1_Send(char chr) {
while(!(USART1->SR & USART_SR_TC));
USART1->DR = chr;
}
void USART1_Send_String(char* str) {
int i=0;
while(str[i])
USART1_Send(str[i++]);
}
// Обработчик всех прерываний от USART1
void USART1_IRQHandler(void) {
// Выясняем, какое именно событие вызвало прерывание. Если это приём байта в RxD - обрабатываем.
if (USART1->SR & USART_SR_RXNE) {
// Сбрасываем флаг прерывания
USART1->SR&=~USART_SR_RXNE;
// Получаем принятый байт
if(USART1->DR=='1') {
GPIO_SetBits(GPIOC, GPIO_Pin_9);
// Отправляем обратно строку "On" с переводом строки
USART1_Send_String("On\r\n");
}
if(USART1->DR=='2') {
GPIO_ResetBits(GPIOC, GPIO_Pin_9);
USART1_Send_String("Off\r\n");
}
}
}
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
//Макрос для проверки состояние определенного светодиода.
#define get_led_state(pin) ((GPIOB->ODR & pin) != 0)
//Функция отправляет байт в UART
void send_to_uart(uint8_t data) {
while(!(USART1->SR & USART_SR_TC));
USART1->DR=data;
}
//Функция отправляет строку в UART
void send_str(char * string) {
uint8_t i=0;
while(string[i]) {
send_to_uart(string[i]);
i++;
}
send_to_uart('\r');
send_to_uart('\n');
}
int main(void)
{
uint8_t uart_data;
uint16_t led;
//Включаем порты и UART1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE);
//Выключаем JTAG (он занимает ноги нужные нам)
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
//Настраиваем первые 10 ног порта B на выход
GPIO_InitTypeDef gpio_port;
gpio_port.GPIO_Pin = 0x3FF;
gpio_port.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_port.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB, &gpio_port);
GPIOB->ODR=0x00;
// Настраиваем ногу PA10 как вход UARTа (RxD)
gpio_port.GPIO_Pin = GPIO_Pin_10;
gpio_port.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &gpio_port);
// Настраиваем ногу PA9 как выход UARTа (TxD)
// Причем не просто выход, а выход с альтернативной функцией
gpio_port.GPIO_Pin = GPIO_Pin_9;
gpio_port.GPIO_Speed = GPIO_Speed_50MHz;
gpio_port.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &gpio_port);
//Заполняем структуру настройками UARTa
USART_InitTypeDef uart_struct;
uart_struct.USART_BaudRate = 9600;
uart_struct.USART_WordLength = USART_WordLength_8b;
uart_struct.USART_StopBits = USART_StopBits_1;
uart_struct.USART_Parity = USART_Parity_No ;
uart_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
uart_struct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
//Инициализируем UART
USART_Init(USART1, &uart_struct);
//Включаем UART
USART_Cmd(USART1, ENABLE);
while(1) //Бесконечный цикл в нем мы проверяем ...
{
if (USART1->SR & USART_SR_RXNE) { // ... не пришло ли что-то в UART ?
uart_data=USART1->DR; //Считываем то что пришло в переменную...
switch(uart_data) { //И выполняем определённое действие...
case '0':
GPIOB->ODR^=GPIO_Pin_0; //Инвертируем состояние ноги №0
break;
case '1':
GPIOB->ODR^=GPIO_Pin_1;
break;
case '2':
GPIOB->ODR^=GPIO_Pin_2;
break;
case '3':
GPIOB->ODR^=GPIO_Pin_3;
break;
case '4':
GPIOB->ODR^=GPIO_Pin_4;
break;
case '5':
GPIOB->ODR^=GPIO_Pin_5;
break;
case '6':
GPIOB->ODR^=GPIO_Pin_6;
break;
case '7':
GPIOB->ODR^=GPIO_Pin_7;
break;
case '8':
GPIOB->ODR^=GPIO_Pin_8;
break;
case '9':
GPIOB->ODR^=GPIO_Pin_9;
break;
case '?': //Печатаем состояние каждого светодиода
send_str("===LEDs state:===");
for (led=1;led<=0x200;led=led<<1) {
if (get_led_state(led)) {
send_str("ON");
} else {
send_str("OFF");
}
}
send_str("=================");
break;
}
}
}
}
Комментариев нет:
Отправить комментарий