Страницы

Ярлыки

ДШИ-200 (1) КСВУ-6 (1) ЛЧМ (1) МДР-23 (1) микроконтроллер (1) перенаправление (1) С (1) структуры (1) учебный курс (1) AC/DC (1) ADC (1) ADS1248 (1) Altium (1) Altuim (1) Amolifer (1) ARM (1) assembler (2) Asynchronous (1) at command (3) at#eaddr (1) at#epassw (1) at#esmtp (1) at#euser (1) at#gprs (1) at#selint=2 (1) at#sgact (1) at#tcpatcmdseq (1) ATX (1) AVR (2) bit (1) boost (1) boot (2) bootlloader (1) C (6) C# (7) C++ (1) CMSIS (1) command (1) CP2101 (1) CSD (1) Danfoss (6) DBGMCU (1) debug (1) debug.ini (1) delegate (1) Discovery (1) DMA (1) DRV8805 (1) DWT (1) e-mail (1) email (1) Exel (1) exFAT (1) FC-051 (1) gl868-dual (2) gl868-dual cmux (1) GPIO (2) GSM (1) I2C (1) IAR (1) ID (1) Invoke (1) Keil (3) LabVIEW (1) Linux (1) LMP7721 (1) LoRa (3) mdmread (1) memory (1) MODBUS (1) Operation Amplifer (1) pack (1) printf (2) printf() (1) RCC (1) retargetting (1) RFM95/96/87/98(W) (1) RS232 (4) RS485 (1) RSAPI.DLL (1) RSS (1) RTC (2) send (2) SerialPort (1) Silabs (1) spl (1) standard peripherals library (1) startup (1) stepper (2) STlink (1) STlink/V2 (2) STM32 (10) stm32 stm32f10x (1) STM32DBG.IN (1) STM32F (19) STM32F103 (4) struct (1) Structure (1) system (1) SystemInit (1) Task (1) telit (5) thread (4) TIM (1) Type Cast (1) UART (1) uni-trend (1) USART (6) USB (1) UT61B (1) viewer (1)

воскресенье, 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;
      }
     }
    }

}

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

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

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