Страницы

воскресенье, 24 ноября 2013 г.

STM32 программирование USART

В микроконтроллерах STM32 имеется не менее одного USART порта.  Главное отличие их в том, что только USART1 подключен к высокоскоростной шине APB2. Все остальные USART подключены к APB1. Для использования USART в STM32 необходимо прежде всего
  • Включить тактиованте шины для USART1
  • Настроить выводы RX / TX для USART1
  • Установите скорость передачи данных для USART1
  • Включить USART1 и его RX-и TX-компонент
Для отправки и приема данных используется регистр DR (Data Register) соответствующего порта USART . При его чтении получаем последний полученный байт. Для передачи байта мы его записываем в этот регистр . Возникает проблема  -  из-за того, что новые данные могут быть записаны в регистр до того как будут прочитаны принятые данные. Одно из решений (неэффективных) проблемы - использовать задержку после записи в регистр байта для передачи перед тем как послать следующий байт или принять ответный байт. Более рациональное решение - использование SR (Status Register) регистра состояния соответствующего USART. Регистр состояния имеет бит, устанавливаемый , если данные передаются, а также бит, устанавливаемый при получены новых данных. При чтении регистра DR, флаг (бит) получения новых данных автоматически сбрасывается. Это решение, которое мы будем использовать в дальнейшем. Кроме этого можно использовать USART1- прерывание для полученных данных. При этом обработчик прерывания вызывается каждый раз были получены новые данные.


Подключаем к проекту файл с именами системных регистров для 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';


Перед началом работы с 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");
    }
  }
}


#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;
      }
     }
    }

}

Комментариев нет:

Отправить комментарий

ваше мнение...