Авг 112012
 

Данная статья – продолжение предыдущей, здесь будет приведен код программы для соединения отладочной платы STM32L-DISCOVERY с компьютером через встроенный модуль USART1. В части настроек модуля USART код для STM32L абсолютно идентичен коду для STM32F, приведенному в предыдущей статье. За исключением настроек делителя системной частоты (регистр USART_BRR) для получения требуемой скорости обмена. Также имеются отличия в настройках выводов портов для этих серий микроконтроллеров.

Схема подключения абсолютно идентична, поскольку в обоих случаях используются микроконтроллеры в 64-выводных корпусах, а они pin-to-pin совместимые. Вывод USART1_TX – это вывод PA9.

usart

Для формирования тактовой частоты задействован внутренний источник HSI. У микроконтроллера серии STM32L его частота равна 16 МГц, тогда как для серии STM32F частота HSI равна 8 МГц. Поэтому для получения скорости обмена 9600 бод, значение коэффициента деления тактовой частоты, записываемое в регистр USART1_BRR, надо рассчитать заново. Можно использовать формулу из предыдущей статьи

Baud rate

Метод перевода получившегося дробного значения USARTDIV в шестнадцатеричную величину для записи в регистр USART1_BRR описан в предыдущей статье STM32. USART. Часть 1.

Далее приведен код программы, при подключении к компьютеру отладочная плата передает строку “STM32L-DISCOVERY”.

#include "stm32l1xx.h"

void Init(void); //Объявление функции инициализации RCC, GPIO, USART
void Usart1_Transmit(uint8_t); //Объявление функции передачи символа через USART
void Usart1_Transmit_str(char* str); //Объявление функции передачи строки через USART


int main()
{
  Init(); //Вызов функции инициализации
  while(1)
  {
    Usart1_Transmit_str("STM32L-DISCOVERY"); //Вызов функции передачи строки через USART
    for(uint32_t i=0; i<0x002FFFFF; i++); //Временная задержка
  }
}

void Init()
{
//RCC
  RCC->CR |= RCC_CR_HSION; //Включаем тактовый генератор HSI
  while(!(RCC_CR_HSIRDY)); //Ждем его стабилизации
  RCC->CFGR |= RCC_CFGR_SW_HSI; //Выбираем источником тактовой частоты SYSCLK генератор HSI
  RCC->CR &= ~RCC_CR_MSION; //Отключаем генератор MSI.
  
//GPIO
  RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //Включаем тактирование порта А
  GPIOA->MODER |= GPIO_MODER_MODER9_1; //PA9 - выход AF
  GPIOA->OTYPER &= ~GPIO_OTYPER_OT_9; //PA9 - выход push-pull
  GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR9); //PA9 - без подтяжки
  GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9; //PA9 - скорость 40 МГц
  /*Далее в разряды AFRH9[3:0] регистра альтернативных функций GPIOA_AFRH записываем 
  значение 0111, тем самым для вывода PA9 задаем значение 
  альтернативной функции - AF7, что соответствует USART1_TX*/
  GPIOA->AFR[1] |= (0x7<<4);  
  
  
//USART1
  RCC->APB2ENR |= RCC_APB2ENR_USART1EN; //Включаем тактирование модуля USART1 
  USART1->CR1 |= USART_CR1_UE; //Включаем USART1
  USART1->CR1 &= ~USART_CR1_M; //Длина слова - 8 бит
  USART1->CR2 &= ~USART_CR2_STOP; //1 стоп-бит
  USART1->BRR = 0x683; //baud rate 9600 при частоте HSI = 16 МГц
  USART1->CR1 |= USART_CR1_TE; //Разрешаем передачу данных
}

//Функци передачи символа через USART
void Usart1_Transmit(uint8_t data)
{
  while(!(USART1->SR & USART_SR_TC)); //Ждем установки флага TC - завершения передачи
  USART1->DR = data;
}

//Функция передачи строки через USART
void Usart1_Transmit_str(char* str)
{
  uint8_t i=0;
  while(str[i])
  {
    Usart1_Transmit(str[i]);
    i++;
  }
  Usart1_Transmit('n');
  Usart1_Transmit('r');
}

Terminal_STM32L

Загрузить проект для платы STM32L-DISCOVERY можно по ссылке:

Проект IAR для передатчика USART1 платы STM32L-DISCOVERY

Другие статьи:

  12 Responses to “STM32. USART. Часть 2.”

  1. Отличные уроки! Скажите, а не планируется поднимать USB, подключение флешки, или каких-либо датчиков на SPI, I2C?

  2. Все со временем будет.

  3. При включении USARTa показания на встроенном экранчике микроконтроллера превращаются в полную белиберду. Можно ли как-нибудь это избежать? Чтобы и USART и экран вместе нормально работали?

  4. Для USART1 и LCD задействованы общие выводы PA9, PA10, можно попробовать сделать «ремапинг» USART_TX и USART_RX на выводы PB6, PB7. В этом случае с LCD пересекаться не будет, но на этих же выводах сидят светодиоды. Может они и не будут мешать, но это надо проверять.

  5. В интернете есть реализация «ремапинга» для микроконтроллеров F серии, а как он делается для L серии?

    • У каждого порта есть регистры выбора альтернативных функций GPIOx_AFRH, GPIOx_AFRH — http://chipspace.ru/stm32-project-iar-ewarm-porty-2/.
      В Reference manual на данную серию можно посмотреть на формат этих регистров.
      Затем ищем в datasheet табличку «Alternate function input/output» со списком альтернативных функций, закрепленных за определенным выводом порта. Например, находим на каких выводах кроме PA9, PA10 доступен выбор USART1_TX (RX). Таперь настраиваем как нужно уже эти выводы, а в их регистрах альтернативных функций задаем номер нужной функции. В коде примера это есть, см. выше, в секции настройки порта такой вот код:
      //GPIO
      RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //Включаем тактирование порта А
      GPIOA->MODER |= GPIO_MODER_MODER9_1; //PA9 — выход AF
      GPIOA->OTYPER &= ~GPIO_OTYPER_OT_9; //PA9 — выход push-pull
      GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR9); //PA9 — без подтяжки
      GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9; //PA9 — скорость 40 МГц
      /*Далее в разряды AFRH9[3:0] регистра альтернативных функций GPIOA_AFRH записываем
      значение 0111, тем самым для вывода PA9 задаем значение
      альтернативной функции — AF7, что соответствует USART1_TX*/
      GPIOA->AFR[1] |= (0x7<<4);

  6. В «Alternate function input/output» для PB6 значение альтернативной функции такое же как и для PA9, значит код будет выглядеть так
    GPIOB->AFR[1] |= (0×7<<4); ?
    Просто настроил порты, забил значение альтернативной функции, но ничего не работает.

  7. Нет, конечно.
    GPIOB->AFR[0]=(0x7<<24); Если делать таким способом, то вроде бы так должно быть (навскидку). Это я обычным сдвигом загоняю число в нужные ячейки. Не совсем видимо понятно из такого кода, что же он делает. Для этого надо посмотреть описание регистров AFRH, AFRL в Reference manual.

  8. Доброго всем времени суток!
    У меня возникла следующая проблема с USART 1, он просто не запускается…
    #include «stm32l1xx.h»
    #include «stm32l1xx_gpio.h»
    #include «stm32l1xx_rcc.h»
    #include «stm32l1xx_syscfg.h»
    #include «stm32l1xx_usart.h»

    #define LED_GREEN_ON GPIO_SetBits(GPIOB, GPIO_Pin_7);

    //Выключить Зеленый Диод, используя стандартную процедуру
    //void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
    //@brief Clears the selected data port bits.
    //@param GPIOx: where x can be (A..H) to select the GPIO peripheral.
    //@param GPIO_Pin: specifies the port bits to be written.
    // This parameter can be any combination of
    // GPIO_Pin_x where x can be (0..15).
    #define LED_GREEN_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_7);

    USART_InitTypeDef USART_InitStructure;

    int main(void)
    {
    char i;

    SystemInit();
    // Не делаем Activaite_HSI для наглядности
    //Activaite_HSI()
    //Включаем HSI
    //RCC -> CR |= RCC_CR_HSION;
    //Ждем стабилизации
    //while(!(RCC_CR_HSIRDY));
    //Выбираем для SYSCLK генератор HSI
    //RCC -> CFGR |= RCC_CFGR_SW_HSI;
    //Выключаем MSI
    //RCC -> CR &= ~RCC_CR_MSION;

    //——————————————————
    // ПОДГОТОВКА ПОРТА REG_B (GPIOB _Pin6 Pin_7 )
    // ВРУЧНУЮ
    //
    // НАЧАЛЬНЫЕ ДАННЫЕ, ДЛЯ REG_B
    //
    // TX: выход push-pull
    // Pin_6; USART1 Tx

    // включаю тактирование порта REG_B
    //
    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;

    //MODER
    //Alt Function GPIOB_Pin_6; USART1 Tx
    //NOT Alt Function GPIOB_Pin_7;

    GPIOB->MODER &= ~0x00006000;
    GPIOB->MODER |= 0x00006000;

    //OTYPER
    GPIOB ->OTYPER &= ~0x00000000;
    GPIOB ->OTYPER |= 0x00000000;

    //OSPEEDR
    GPIOB->OSPEEDR &= ~0x0000A000;
    GPIOB->OSPEEDR |= 0x0000A000;

    //PUPDR
    GPIOB->PUPDR &= ~0x00000000;
    GPIOB->PUPDR |= 0x00000000;

    //AFRL
    GPIOB->AFR[0] &= ~0x07000000;
    GPIOB->AFR[0] |= 0x07000000;

    //AFRH
    GPIOB->AFR[1] &= ~0x00000000;
    GPIOB->AFR[1] |= 0x00000000;

    // USART1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    // Заполняем структуру
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;

    // Инициируем USART 1
    USART_Init(USART1, &USART_InitStructure);

    USART1->BRR = 0xFFF0; // Это, естесственно, от «фонаря»
    /* и вот «ЗАМОРОЧКА»
    // ПОКА НЕ ЗАПИШЕМ в USART1->BRR значение, USART 1 НЕ РАБОТАЕТ
    //ПОТОМУ, ЧТО после USART_Init(USART1, &USART_InitStructure);
    * В USART1->BRR УСТАНАВЛИВАЕТСЯ 0x00000000 (?)
    //Я нашел, что при выполнении процедуры
    * USART_Init(USART1, &USART_InitStructure);
    * .
    * .в части:
    *
    * stm32l1xx_usart.c
    *
    *
    * USART BRR Configuration ————————
    Configure the USART Baud Rate —————
    после выполнения запроса:
    RCC_GetClocksFreq(&RCC_ClocksStatus);

    if (USARTx == USART1)
    {
    apbclock = RCC_ClocksStatus.PCLK2_Frequency;
    }
    else
    {
    apbclock = RCC_ClocksStatus.PCLK1_Frequency;
    }

    значения
    RCC_ClocksStatus.PCLK2_Frequency; = 0x00000000 (?)
    RCC_ClocksStatus.PCLK1_Frequency; = 0x00000000 (?),

    хотя, теоретически, при условии, что HSI активизорован,
    эти значения должны совпадать с

    RCC_ClocksStatus.SYSCLK_Frequency = HSI_VALUE;
    */

    //Включаем USART1
    USART1->CR1 |= USART_CR1_UE;

    LED_GREEN_ON;

    while(1)
    {
    //Ждем установки флага TC — завершения передачи
    while(!(USART1->SR & USART_SR_TC))
    {LED_GREEN_ON;}

    //передача символа через USART
    USART1->DR = 0x00;//i;

    LED_GREEN_OFF;
    }
    }

  9. Спасибо.
    Обращу Ваше внимание на то, что нижеследующие команды — ошибочны

    GPIOB->MODER &= ~0×00006000; — Так сейчас

    Надо так GPIOB->MODER &= ~0×0000F000

    GPIOB->MODER |= 0×00006000;

    //OTYPER
    GPIOB ->OTYPER &= ~0×00000000; Так сейчас

    Надо так GPIOB ->OTYPER &= ~0×000000c0

    GPIOB ->OTYPER |= 0×00000000

    //OSPEEDR
    GPIOB->OSPEEDR &= ~0x0000A000; — Так сейчас

    Надо так GPIOB->OSPEEDR &= ~0x0000F000

    GPIOB->OSPEEDR |= 0x0000A000;

    //AFRL
    GPIOB->AFR[0] &= ~0×07000000; Так сейчас

    Надо так GPIOB->AFR[0] &= ~0×0F000000;

    GPIOB->AFR[0] |= 0×07000000;

    С уважением, Сергей.

    • Сергей, HSI не активирован, источником тактирования в этом проекте является MSI. Если я правильно понял, мк должен работать от HSI? Но строки активации этого генератора закомментированы, так и надо или я чего-то не понял?
      У меня в отладчике IAR после инициализации USART1 получилось:
      USART1_BRR = 0x000000DA (DIV_Fraction = 0xA, DIV_Mantissa = 0x00D).
      В данном случае точку останова поставил на строке, следующей за заполнением структуры регистров USART1, то есть тут
      USART1->BRR = 0xFFF0;
      Как видно, в регистре USART1_BRR вовсе не нули. Так что, разбирайтесь!
      И еще, что за конструкция
      GPIOB ->OTYPER |= 0×00000000?
      Она же ничего не выполняет.

      • Большое спасибо!

        …. Но строки активации этого генератора закомментированы, так и надо или я чего-то не понял?…..

        Я специально закомментировал эти строчки, так как при MSI скорость меньше, и моргание синего LED будет нагляднее, только и всего. Поэтому ввел и эту инструкцию USART1->BRR = 0xFFF0; , что бы медленнее работало и, опять же для наглядности, ведь, как оказалось, логика выхода USART — отрицательная, то есть ЕДИНИЦА — это 0v (земля) и при быстрой передачи синий LED все время светится.

        …И еще, что за конструкция
        GPIOB ->OTYPER |= 0×00000000?
        Она же ничего не выполняет….

        Да, это реально так, но когда писал инструкции, ТУПО выполнял алгоритм
        1.СБРОСИТЬ БИТЫ
        2.УСТАНОВИТЬ БИТЫ.

        Ещё мною подмечено, если установить
        USART1->BRR = 0x0000;
        или
        USART1->BRR = 0xFFFF;

        USART работать не будет.

        В дополнение: При работе от MSI для скорости 9600, ручным подбором установил значение USART1->BRR = 0x000D;

        Ещё раз Спасибо. Буду разбираться дальше
        С Уважением, Сергей