STM8S+SDCC+SPL: использование модуля UART1 на примере функции printf()

UART обладает двумя важными преимуществами перед остальными интерфейсами: во-первых, через TTL-конвертер его напрямую можно подключить к компьютеру, а во-вторых, линии связи между двумя узлами могут достигать 50 метров, что позволяет без проблем построить, к примеру, локальную сеть типа SmartHome. В STM8 скорость передачи через UART может достигать 1Mbit/s при частоте системной шины в 16MHz.

Микроконтроллеры STM8S могут обладать несколькими UART модулями,правда характеристики этих модулей немного разнятся:

Использование UART с помощью стандартной периферийной библиотеки(далее SPL), не сложнее, чем в AVR или даже Arduino. Библиотека, в папке Examples содержит готовые примеры использования UART, которые подробно прокомментированы. НО что бы не скатиться до потребительского отношения, бездумно используя чужой код, я предлагаю пошуршать немного мануалами, чтобы понять, чем же все-таки являются USART модули в STM8, и как ими пользоваться максимально эффективно.

Основные возможности UART1 в stm8s103f3:

LIN и CAN это локальные сети созданные для использования в автомобилестроении:

    Основные задачи, возлагаемые на  LIN консорциумом европейских автомобильных производителей, — объединение автомобильных подсистем и узлов (таких как дверные замки, стеклоочистители, стеклоподъёмники, управление магнитолой и климат-контролем, электролюк и так далее) в единую электронную систему. LIN-протокол утверждён Европейским Автомобильным Консорциумом как дешёвое дополнение к сверхнадёжному протоколу  CAN.

    LIN и CAN дополняют друг друга и позволяют объединить все электронные автомобильные приборы в единую многофункциональную бортовую сеть. Причём область применения CAN — участки, где требуется сверхнадёжность и скорость; область же применения LIN — объединение дешёвых узлов, работающих с малыми скоростями передачи информации на коротких дистанциях и сохраняющих при этом универсальность, многофункциональность, а также простоту разработки и отладки.

Так же имеется поддержка IrDA

Сам порт IrDA основан на архитектуре коммуникационного СОМ-порта ПК, который использует универсальный асинхронный приемо-передатчик UART и работает со скоростью передачи данных 2400–115200 bps.

Связь в IrDA полудуплексная, т.к. передаваемый ИК-луч неизбежно засвечивает соседний PIN-диодный усилитель приемника. Воздушный промежуток между устройствами позволяет принять ИК-энергию только от одного источника в данный момент.  

Кроме этого имеется еще Smartcard

Интерфейс является синхронным режимом USART-драйвера, это значит, что передачу каждого бита информации мы синхронизируем частотой на выводе CLK, но здесь есть одно важное отличие от прочих синхронных интерфейсов (вроде того же SPI): для тактирования одного бита информации нужен не один импульс на CLK, а 372 импульса (это магическое число прописано в 3 части ISO7816, и носит название ETU (Elementary Time Unit)), т.е., один бит данных тактируется каждым 372-м (в идеальном случае) фронтом. Сама частота должна лежать в пределах от 1 до 5 МГц.

Как видно, вариантов использования UART много, но сейчас нас будет интересовать классический UART протокол: 8N1.

Регистры модуля UART1 в SPL описываются следующей структурой:

typedef struct UART1_struct
{
  __IO uint8_t SR;   /*!< UART1 status register */
  __IO uint8_t DR;   /*!< UART1 data register */
  __IO uint8_t BRR1; /*!< UART1 baud rate register */
  __IO uint8_t BRR2; /*!< UART1 DIV mantissa[11:8] SCIDIV fraction */
  __IO uint8_t CR1;  /*!< UART1 control register 1 */
  __IO uint8_t CR2;  /*!< UART1 control register 2 */
  __IO uint8_t CR3;  /*!< UART1 control register 3 */
  __IO uint8_t CR4;  /*!< UART1 control register 4 */
  __IO uint8_t CR5;  /*!< UART1 control register 5 */
  __IO uint8_t GTR;  /*!< UART1 guard time register */
  __IO uint8_t PSCR; /*!< UART1 prescaler register */
}
UART1_TypeDef;

DR - регистр данных, BRRx - определяют скорость интерфейса, SR - флаговые/статусные регистры, CRх - управляющие режимами работы UART регистры, PSCR - позволяет понизить тактовую частоту UART модуля. Если к примеру, скорость передачи 9600 bod, то незачем модуль гонять вхолостую, можно поставить делитель на 64. GTR - Guard Time Register используется в Smartcard, задает величину защищенного интервала в тактах системной шины тактирования.

Функцией UART1_DeInit(), в регистры записываются следующие значения по умолчанию:

#define UART1_SR_RESET_VALUE   ((uint8_t)0xC0)
#define UART1_BRR1_RESET_VALUE ((uint8_t)0x00)
#define UART1_BRR2_RESET_VALUE ((uint8_t)0x00)
#define UART1_CR1_RESET_VALUE  ((uint8_t)0x00)
#define UART1_CR2_RESET_VALUE  ((uint8_t)0x00)
#define UART1_CR3_RESET_VALUE  ((uint8_t)0x00)
#define UART1_CR4_RESET_VALUE  ((uint8_t)0x00)
#define UART1_CR5_RESET_VALUE  ((uint8_t)0x00)
#define UART1_GTR_RESET_VALUE  ((uint8_t)0x00)
#define UART1_PSCR_RESET_VALUE ((uint8_t)0x00)

Функционал модуля UART1 реализуется следующими функциями:

void UART1_DeInit(void);
void UART1_Init(uint32_t BaudRate, UART1_WordLength_TypeDef WordLength,
                UART1_StopBits_TypeDef StopBits, UART1_Parity_TypeDef Parity,
                UART1_SyncMode_TypeDef SyncMode, UART1_Mode_TypeDef Mode);
void UART1_Cmd(FunctionalState NewState);
void UART1_ITConfig(UART1_IT_TypeDef UART1_IT, FunctionalState NewState);
void UART1_HalfDuplexCmd(FunctionalState NewState);
void UART1_IrDAConfig(UART1_IrDAMode_TypeDef UART1_IrDAMode);
void UART1_IrDACmd(FunctionalState NewState);
void UART1_LINBreakDetectionConfig(UART1_LINBreakDetectionLength_TypeDef UART1_LINBreakDetectionLength);
void UART1_LINCmd(FunctionalState NewState);
void UART1_SmartCardCmd(FunctionalState NewState);
void UART1_SmartCardNACKCmd(FunctionalState NewState);
void UART1_WakeUpConfig(UART1_WakeUp_TypeDef UART1_WakeUp);
void UART1_ReceiverWakeUpCmd(FunctionalState NewState);
uint8_t UART1_ReceiveData8(void);
uint16_t UART1_ReceiveData9(void);
void UART1_SendData8(uint8_t Data);
void UART1_SendData9(uint16_t Data);
void UART1_SendBreak(void);
void UART1_SetAddress(uint8_t UART1_Address);
void UART1_SetGuardTime(uint8_t UART1_GuardTime);
void UART1_SetPrescaler(uint8_t UART1_Prescaler);
FlagStatus UART1_GetFlagStatus(UART1_Flag_TypeDef UART1_FLAG);
void UART1_ClearFlag(UART1_Flag_TypeDef UART1_FLAG);
ITStatus UART1_GetITStatus(UART1_IT_TypeDef UART1_IT);
void UART1_ClearITPendingBit(UART1_IT_TypeDef UART1_IT);

Пример программы для пересылки данных с микроконтроллера на компьютер через UART:

#include "stm8s.h"
#include "stm8s_gpio.h"
#include "stm8s_clk.h"
#include "stm8s_tim4.h"
#include "stm8s_uart1.h"
#include "stdio.h"

#define LED_PORT GPIOB
#define LED GPIO_PIN_5

#define TIM4_PERIOD       124

#define PUTCHAR_PROTOTYPE void putchar (char c)

ErrorStatus status = FALSE;
volatile uint16_t count;
uint16_t i;

INTERRUPT_HANDLER(IRQ_Handler_TIM4, 23)
{
    if (count)
        count--;

    TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
}

void delay_ms(uint16_t ms)
{
        TIM4_Cmd(DISABLE);       // stop
        TIM4_TimeBaseInit(TIM4_PRESCALER_128, TIM4_PERIOD);
        TIM4_ClearFlag(TIM4_FLAG_UPDATE);
        TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);

        count = ms;

        TIM4_Cmd(ENABLE);       // let's go

    while(count);
}


int main( void )
{

    // ----------- GPIO CONFIG -------------------
    GPIO_DeInit(LED_PORT);
    GPIO_Init(LED_PORT, LED, GPIO_MODE_OUT_PP_LOW_FAST);

    // ---------- CLK CONFIG -----------------------
    CLK_DeInit();

        CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
    CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1); // set 16 MHz for CPU

    TIM4_DeInit();
    // uncomment if use HSE on Quartz
    //status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE,
        //                CLK_CURRENTCLOCKSTATE_DISABLE);

    // ------------ UART1 -------------------
    UART1_DeInit();

    // 8N1
    UART1_Init((uint32_t)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO,
              UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);


    enableInterrupts();
    i=0;
    for(;;)
    {
        GPIO_WriteReverse(LED_PORT, LED);
        delay_ms(1000);

        printf("count: %u\n",++i);
    }
}


PUTCHAR_PROTOTYPE
{
    // Write a character to the UART1
    UART1_SendData8(c);
    // Loop until the end of transmission 
    while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
}

Так же как в AVR, для использования функции printf() нужно только задать функцию putchar(char c), после чего системная библиотека сделает все за вас. Кстати, прошивка вместе с printf(), начинает весить уже от 5 Kбайт.

Результат работы выглядит как-то так:

я предлагаю заглянуть в код функции UART1_SendData8(c):

void UART1_SendData8(uint8_t Data)
{
  /* Transmit Data */
  UART1->DR = Data;
}

а так же UART1_GetFlagStatus(UART1_FLAG_TXE):

FlagStatus UART1_GetFlagStatus(UART1_Flag_TypeDef UART1_FLAG)
{
  FlagStatus status = RESET;

  /* Check parameters */
  assert_param(IS_UART1_FLAG_OK(UART1_FLAG));


  /* Check the status of the specified UART1 flag*/
  if (UART1_FLAG == UART1_FLAG_LBDF)
  {
    if ((UART1->CR4 & (uint8_t)UART1_FLAG) != (uint8_t)0x00)
    {
      /* UART1_FLAG is set*/
      status = SET;
    }
    else
    {
      /* UART1_FLAG is reset*/
      status = RESET;
    }
  }
  else if (UART1_FLAG == UART1_FLAG_SBK)
  {
    if ((UART1->CR2 & (uint8_t)UART1_FLAG) != (uint8_t)0x00)
    {
      /* UART1_FLAG is set*/
      status = SET;
    }
    else
    {
      /* UART1_FLAG is reset*/
      status = RESET;
    }
  }
  else
  {
    if ((UART1->SR & (uint8_t)UART1_FLAG) != (uint8_t)0x00)
    {
      /* UART1_FLAG is set*/
      status = SET;
    }
    else
    {
      /* UART1_FLAG is reset*/
      status = RESET;
    }
  }
  /* Return the UART1_FLAG status*/
  return status;
}

но самая интересная функция, это конечно UART1_Init():

void UART1_Init(uint32_t BaudRate, UART1_WordLength_TypeDef WordLength,
                UART1_StopBits_TypeDef StopBits, UART1_Parity_TypeDef Parity,
                UART1_SyncMode_TypeDef SyncMode, UART1_Mode_TypeDef Mode)
{
  uint32_t BaudRate_Mantissa = 0, BaudRate_Mantissa100 = 0;

  /* Check the parameters */
  assert_param(IS_UART1_BAUDRATE_OK(BaudRate));
  assert_param(IS_UART1_WORDLENGTH_OK(WordLength));
  assert_param(IS_UART1_STOPBITS_OK(StopBits));
  assert_param(IS_UART1_PARITY_OK(Parity));
  assert_param(IS_UART1_MODE_OK((uint8_t)Mode));
  assert_param(IS_UART1_SYNCMODE_OK((uint8_t)SyncMode));

  /* Clear the word length bit */
  UART1->CR1 &= (uint8_t)(~UART1_CR1_M);

  /* Set the word length bit according to UART1_WordLength value */
  UART1->CR1 |= (uint8_t)WordLength;

  /* Clear the STOP bits */
  UART1->CR3 &= (uint8_t)(~UART1_CR3_STOP);
  /* Set the STOP bits number according to UART1_StopBits value  */
  UART1->CR3 |= (uint8_t)StopBits;

  /* Clear the Parity Control bit */
  UART1->CR1 &= (uint8_t)(~(UART1_CR1_PCEN | UART1_CR1_PS  ));
  /* Set the Parity Control bit to UART1_Parity value */
  UART1->CR1 |= (uint8_t)Parity;

  /* Clear the LSB mantissa of UART1DIV  */
  UART1->BRR1 &= (uint8_t)(~UART1_BRR1_DIVM);
  /* Clear the MSB mantissa of UART1DIV  */
  UART1->BRR2 &= (uint8_t)(~UART1_BRR2_DIVM);
  /* Clear the Fraction bits of UART1DIV */
  UART1->BRR2 &= (uint8_t)(~UART1_BRR2_DIVF);

  /* Set the UART1 BaudRates in BRR1 and BRR2 registers according to UART1_BaudRate value */
  BaudRate_Mantissa    = ((uint32_t)CLK_GetClockFreq() / (BaudRate << 4));
  BaudRate_Mantissa100 = (((uint32_t)CLK_GetClockFreq() * 100) / (BaudRate << 4));
  /* Set the fraction of UART1DIV  */
  UART1->BRR2 |= (uint8_t)((uint8_t)(((BaudRate_Mantissa100 - (BaudRate_Mantissa * 100)) << 4) / 100) & (uint8_t)0x0F);
  /* Set the MSB mantissa of UART1DIV  */
  UART1->BRR2 |= (uint8_t)((BaudRate_Mantissa >> 4) & (uint8_t)0xF0);
  /* Set the LSB mantissa of UART1DIV  */
  UART1->BRR1 |= (uint8_t)BaudRate_Mantissa;

  /* Disable the Transmitter and Receiver before setting the LBCL, CPOL and CPHA bits */
  UART1->CR2 &= (uint8_t)~(UART1_CR2_TEN | UART1_CR2_REN);
  /* Clear the Clock Polarity, lock Phase, Last Bit Clock pulse */
  UART1->CR3 &= (uint8_t)~(UART1_CR3_CPOL | UART1_CR3_CPHA | UART1_CR3_LBCL);
  /* Set the Clock Polarity, lock Phase, Last Bit Clock pulse */
  UART1->CR3 |= (uint8_t)((uint8_t)SyncMode & (uint8_t)(UART1_CR3_CPOL |
                                                        UART1_CR3_CPHA | UART1_CR3_LBCL));

  if ((uint8_t)(Mode & UART1_MODE_TX_ENABLE))
  {
    /* Set the Transmitter Enable bit */
    UART1->CR2 |= (uint8_t)UART1_CR2_TEN;
  }
  else
  {
    /* Clear the Transmitter Disable bit */
    UART1->CR2 &= (uint8_t)(~UART1_CR2_TEN);
  }
  if ((uint8_t)(Mode & UART1_MODE_RX_ENABLE))
  {
    /* Set the Receiver Enable bit */
    UART1->CR2 |= (uint8_t)UART1_CR2_REN;
  }
  else
  {
    /* Clear the Receiver Disable bit */
    UART1->CR2 &= (uint8_t)(~UART1_CR2_REN);
  }
  /* Set the Clock Enable bit, lock Polarity, lock Phase and Last Bit Clock 
  pulse bits according to UART1_Mode value */
  if ((uint8_t)(SyncMode & UART1_SYNCMODE_CLOCK_DISABLE))
  {
    /* Clear the Clock Enable bit */
    UART1->CR3 &= (uint8_t)(~UART1_CR3_CKEN);
  }
  else
  {
    UART1->CR3 |= (uint8_t)((uint8_t)SyncMode & UART1_CR3_CKEN);
  }
}

И здесь кроется довольно массивный "подводный камень". Дело в следущем. Как помнится, в AVR была хитрая формула для преобразования скорости передачи в значение регистра UBRR. В STM8 имеется не менее хитрая формула для регистров BRRx:

своя табличка тоже наличествует:

Как не трудно заметить, функция прямо пропорциональна fMASTER. Значение fMASTER UART1_Init() берет из модуля CLK с помощью функции CLK_GetClock():

BaudRate_Mantissa    = ((uint32_t)CLK_GetClockFreq() / (BaudRate << 4));
BaudRate_Mantissa100 = (((uint32_t)CLK_GetClockFreq() * 100) / (BaudRate << 4));

А сама CLK_GetClock() выглядит так:

uint32_t CLK_GetClockFreq(void)
{
  uint32_t clockfrequency = 0;
  CLK_Source_TypeDef clocksource = CLK_SOURCE_HSI;
  uint8_t tmp = 0, presc = 0;

  // Get CLK source.
  clocksource = (CLK_Source_TypeDef)CLK->CMSR;

  if (clocksource == CLK_SOURCE_HSI)
  {
    tmp = (uint8_t)(CLK->CKDIVR & CLK_CKDIVR_HSIDIV);
    tmp = (uint8_t)(tmp >> 3);
    presc = HSIDivFactor[tmp];
    clockfrequency = HSI_VALUE / presc;
  }
  else if ( clocksource == CLK_SOURCE_LSI)
  {
    clockfrequency = LSI_VALUE;
  }
  else
  {
    clockfrequency = HSE_VALUE;
  }

  return((uint32_t)clockfrequency);
}

Так вот. Если чип будет использовать внешний резонатор HSE, значение частоты резонатора будет браться из именованной константы HSE_VALUE в stm8s.h:

 #if !defined  HSE_Value
 #if defined (STM8S208) || defined (STM8S207) || defined (STM8S007) || defined (STM8AF52Ax) || \
     defined (STM8AF62Ax) || defined (STM8AF622x)
  #define HSE_VALUE ((uint32_t)24000000) /* Value of the External oscillator in Hz*/
 #else
  #define HSE_VALUE ((uint32_t)16000000) /* Value of the External oscillator in Hz*/
 #endif /* STM8S208 || STM8S207 || STM8S007 || STM8AF62Ax || STM8AF52Ax || STM8AF622x */
#endif /* HSE_Value */

.т.е. если ваш кварц не на 16 МГц, и вы не вписали частоту кварца во время компиляции, или не поправили заголовочный файл stm8s.h, то работать корректно ваш модуль UART не будет. Такой вот тест на внимательность.

Разобравшись c BRRx, осталось пробежаться по управляющим регистрам UART1_CRx. Общая карта регистров для модуля UART1 в STM8S выглядит так:

UART1_Init() для конфигурации UART1 использует регистры: CR1, CR2, CR3.

В CR1 у нас устанвливается длина фрейма равной восьми(установкой бита 4 M), а также сбрасывается аппаратный контроль четности( биты 2 PCEN и бит 1 PS) . Для ясности напомню формат UART кадра:

  • Остальные биты:
  • Биты 7 и 6 отвечают за передачу кадром 9 бит. Если не ошибаюсь, такое используется в Multi-Processor communication когда локальную сеть строят на одном UART модуле. Тогда несколько бит используются для адресации устройства. Подробнее об этом можно почитать здесь: "Время говорить с камнями или USART Multi-processor Communication Mode" , сам я с этой штукой ни разу не сталкивался.
  • Бит 5 отключает тактирование от UART, в целях энергосбережения.
  • Бит 3 WAKE - определяет способ пробуждения из энергосберегающего режима. 0 - по освобожлению линии, 1 - по принятию адреса.
  • Бит 0 PIEN - разрешает/запрещает прерывание по четности. Прерывание генерируется когда устанавливается флаг PE в регистре UART1_SR.

Кстати, про прерывания. Прерывания UART могут вызывать следующие события:

Полезно будет эту табличку запомнить на будущее. А пока рассмотрим регистр UART_CR2:

Здесь нас интересуют биты 3 TEN и 2 REN, разрешение передачи и приема соответственно. В принципе, т.к. микроконтроллер работает только на передачу, можно было выставить только TEN, тогда пин Rx можно было бы использовать в других задачах.

Биты с седьмого по четвертый устанавливают источник вызова прерывания.

Бит RWU, определяет находится ли UART в "спящем" режиме или в активном. Как я понял из описания, UART можно вывести из режима сна, передачей специальной последовательности.

SBK - этот бит используется для отправки разрывающего стоп-бита. Устанавливается программно, сбрасывается аппаратно.

Регистр UARTx_CR3:

Здесь нас интересуют STOP биты 5:6, которые определяют количество стоп-битов: одни, два или полтора;

LINEN включает LIN режим;

  • Остальные биты настраивают вывод синхронизирующего тактового сигнала SCLK pin для работы USART в синхронном режиме.
  • CLKEN включает выдачу тактового сигнала для SCLK pin.
  • CPOL задает полярность SCLK pin;
  • CPHA задет фазу SCLK pin. Передача бита данных будет синхронизирована по первому фронту или по второму;
  • LBCL задет вывод последнего бита данных на SCLK pin. Т.к. USART передает фрейм младшим битом вперед, то последним битом будет соответственно старший 8-й или 9-й бит данных, в зависимости от формата фрейма.

Использование USART1 в чипе STM8L051F3 (добавлено 31 августа 2016г.)

В L-серии UART модули лишены LIN и CAN интерфейсов, в остальном же соответствуют USART модулям в STM8S.

Струтура писывающая модуль USART в SPL идентична структуре в S-серии, за тем исключением, что она общаяя для всех модулей:

typedef struct USART_struct
{
  __IO uint8_t SR;   /*!<  USART status register  */
  __IO uint8_t DR;   /*!<  USART data register     */
  __IO uint8_t BRR1; /*!<  USART baud rate register   */
  __IO uint8_t BRR2; /*!<  USART DIV mantissa[11:8] SCIDIV fraction */
  __IO uint8_t CR1;  /*!<  USART control register 1     */
  __IO uint8_t CR2;  /*!<  USART control register 2     */
  __IO uint8_t CR3;  /*!<  USART control register 3      */
  __IO uint8_t CR4;  /*!< USART control register 4      */
  __IO uint8_t CR5;  /*!<  USART control register 5       */
  __IO uint8_t GTR;  /*!<  USART guard time register     */
  __IO uint8_t PSCR; /*!<  USART prescaler register     */
}
USART_TypeDef;

Поэтому во всех функциях SPL имеется дополнительный параметр: USART_TypeDef* USARTx - номер модуля USART:

/*  Function used to set the USART configuration to the default reset state ***/
void USART_DeInit(USART_TypeDef* USARTx);

/* Initialization and Configuration functions *********************************/
void USART_Init(USART_TypeDef* USARTx, uint32_t BaudRate, USART_WordLength_TypeDef
                USART_WordLength, USART_StopBits_TypeDef USART_StopBits,
                USART_Parity_TypeDef USART_Parity, USART_Mode_TypeDef USART_Mode);
void USART_ClockInit(USART_TypeDef* USARTx, USART_Clock_TypeDef USART_Clock,
                     USART_CPOL_TypeDef USART_CPOL, USART_CPHA_TypeDef USART_CPHA,
                     USART_LastBit_TypeDef USART_LastBit);
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
void USART_SetPrescaler(USART_TypeDef* USARTx, uint8_t USART_Prescaler);
void USART_SendBreak(USART_TypeDef* USARTx);

/* Data transfers functions ***************************************************/
void USART_SendData8(USART_TypeDef* USARTx, uint8_t Data);
void USART_SendData9(USART_TypeDef* USARTx, uint16_t Data);
uint8_t USART_ReceiveData8(USART_TypeDef* USARTx);
uint16_t USART_ReceiveData9(USART_TypeDef* USARTx);

/* Multi-Processor Communication functions ************************************/
void USART_WakeUpConfig(USART_TypeDef* USARTx, USART_WakeUp_TypeDef USART_WakeUp);
void USART_ReceiverWakeUpCmd(USART_TypeDef* USARTx, FunctionalState NewState);
void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address);

/* Half-duplex mode function **************************************************/
void USART_HalfDuplexCmd(USART_TypeDef* USARTx, FunctionalState NewState);

/* Smartcard mode functions ***************************************************/
void USART_SmartCardCmd(USART_TypeDef* USARTx, FunctionalState NewState);
void USART_SmartCardNACKCmd(USART_TypeDef* USARTx, FunctionalState NewState);
void USART_SetGuardTime(USART_TypeDef* USARTx, uint8_t USART_GuardTime);

/* IrDA mode functions ********************************************************/
void USART_IrDAConfig(USART_TypeDef* USARTx, USART_IrDAMode_TypeDef USART_IrDAMode);
void USART_IrDACmd(USART_TypeDef* USARTx, FunctionalState NewState);

/* DMA transfers management functions *****************************************/
void USART_DMACmd(USART_TypeDef* USARTx, USART_DMAReq_TypeDef USART_DMAReq,
                  FunctionalState NewState);

/* Interrupts and flags management functions **********************************/
void USART_ITConfig(USART_TypeDef* USARTx, USART_IT_TypeDef USART_IT,
                    FunctionalState NewState);
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, USART_FLAG_TypeDef USART_FLAG);
void USART_ClearFlag(USART_TypeDef* USARTx, USART_FLAG_TypeDef USART_FLAG);
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, USART_IT_TypeDef USART_IT);
void USART_ClearITPendingBit(USART_TypeDef* USARTx);//, USART_IT_TypeDef USART_IT);

Пример использования printf() для STM8L051F3 выглядит следующим образом:

#include "stm8l.h"
#include "stm8l_gpio.h"
#include "stm8l_clk.h"
#include "stm8l_tim4.h"
#include "stm8l_usart.h"
#include "stdio.h"

#define PORT GPIOB
#define LED  GPIO_Pin_1
#define TIM4_PERIOD 124

#define PUTCHAR_PROTOTYPE void putchar (char c)

volatile uint16_t count;
uint8_t i;

INTERRUPT_HANDLER(IRQ_Handler_TIM4, 25)
{
  if (count)
    count--;

  TIM4_ClearITPendingBit(TIM4_IT_Update);
}

void delay_ms(uint16_t ms)
{
        TIM4_Cmd(DISABLE);       // stop

        TIM4_TimeBaseInit(TIM4_Prescaler_128, TIM4_PERIOD);
        TIM4_ClearFlag(TIM4_FLAG_Update);
        TIM4_ITConfig(TIM4_IT_Update, ENABLE);

        count = ms;

        TIM4_Cmd(ENABLE);       // let's go

  while(count);
}

int main( void )
{
  // ---------   GPIO Config ---------------------------

  GPIO_DeInit(PORT);

  GPIO_Init(PORT, LED, GPIO_Mode_Out_PP_Low_Fast);

  // ---------- CLK Config -----------------------
  CLK_DeInit();
  CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);
  CLK_PeripheralClockConfig(CLK_Peripheral_TIM4, ENABLE);
  CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);
  // ---------- TIM4 Init -----------------------------
  TIM4_DeInit();

  // ---------- USART Init ---------------------------
  USART_DeInit(USART1);

  USART_Init(USART1, (uint32_t)9600, USART_WordLength_8b, USART_StopBits_1,
                   USART_Parity_No, (USART_Mode_TypeDef)(USART_Mode_Tx | USART_Mode_Rx));

  enableInterrupts();
  i=0;

  for(;;)
  {
      delay_ms(1000);
      GPIO_ToggleBits(PORT, LED);
      printf("count: %d\n",++i);
  }

}

PUTCHAR_PROTOTYPE
{
  /* Write a character to the USART */
  USART_SendData8(USART1, c);
  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);

//    return (c);
}

Здесь ножка PC5 подключается к RX-пину TTL-конвертера, земля микросхемы подключается к земле конвертера. И желательно что бы конвертер питался ыот напряжения 3.3 Вольт.

Результат работы выглядит аналогично примеру для S-серии.

Скачать архив с полными исходниками можно здесь: скачать

 
 

 

Добавить комментарий

Обратная связь

Интересуют вопросы реализации алгоритмов, программирования, выбора электроники и прочая информация, постараюсь осветить в отдельных статьях

пишите мне на netdm@mail.ru