首页 > 其他 > 详细

STM32的串口通信UART/TTL

时间:2021-04-28 16:17:11      阅读:17      评论:0      收藏:0      [点我收藏+]

常用的串口pin

STM32的串口是基础通信方式, 每个型号都带多组串口, 一般都使用默认的组, 可以参考芯片的datasheet, 去看pinout and pin definitions, 对于stm32f103c8t6, 这是48pin的芯片, 提供3组串口, 如果使用3组, 各组串口的pin脚为

  • USART2 - A2, A3
    • PA0: USART2_CTS
    • PA1: USART2_RTS
    • PA2: USART2_TX
    • PA3: USART2_RX
    • PA4: USART2_CK
  • USART1 - A9, A10
    • PA8: USART1_CK
    • PA9: USART1_TX
    • PA10: USART1_RX
    • PA11: USART1_CTS
    • PA12: USART1_RTS
  • USART3 - B10, B11
    • PB10: USART3_TX
    • PB11: USART3_RX
    • PB12: USART3_CK
    • PB13: USART1_CTS
    • PB14: USART1_RTS

串口通信编程

一般通过以下的步骤实现串口通信

1. 申请内存作为buffer, 声明标记位和buffer指针

简单的例子

u8 usart_buf[100] = {0};
u16 index1 = 0, flag1 = 0;

复杂的例子

#define TTL_BufferLength    ((uint16_t)0x0040)
#define TTL_WriteOk         ((uint16_t)0x0000)
#define TTL_BufferOverrun   ((uint16_t)0x0001) // full flag
#define TTL_BufferUnderrun  ((uint16_t)0x0002) // empty flag

/* Private types -------------------------------------------------------------*/
typedef struct
{
  uint16_t size;  /* The size of the buffer */
  uint16_t start; /* The index of the next character to send */
  uint16_t end;   /* The index at which to write the next character */
  char* elems;    /* The location in memory of the buffer */
} TTL_BufferTypeDef;
 
/* Private variables ----------------------------------------------------------*/
 
TTL_BufferTypeDef cb;

/* Private Methods -----------------------------------------------------------*/
void TTL_Buffer_Init()
{
  cb.size = TTL_BufferLength;
  cb.start = 0;
  cb.end = 0;
  cb.elems = calloc(cb.size, sizeof(char));
}
 
void TTL_Buffer_Free()
{
  free(cb.elems);
}
 
uint16_t TTL_Buffer_IsFull()
{
  return (cb.end + 1) % cb.size == cb.start;
}
 
uint16_t TTL_Buffer_IsEmpty()
{
  return cb.end == cb.start;
}

uint16_t TTL_Buffer_Write(char c)
{
  // check for a buffer overrun
  if (TTL_Buffer_IsFull()) {
    return TTL_BufferOverrun;
  } else {
    cb.elems[cb.end] = c;
    cb.end = (cb.end + 1) % cb.size;
  }
  return TTL_WriteOk;
}
 
uint16_t TTL_Buffer_Read(char* c)
{
  // check for a buffer underrun
  if (TTL_Buffer_IsEmpty()) {
    return TTL_BufferUnderrun;
  } else {
    *c = cb.elems[cb.start];
    cb.start = (cb.start + 1) % cb.size;
  }
}

2. 初始化UART端口: 使能GPIO, UART, NVIC

/* Public Methods -----------------------------------------------------------*/
void TTL_Init()
{
  // Structures to hold the initialisation data
  GPIO_InitTypeDef GPIO_InitStruct;
  USART_InitTypeDef USART_InitStruct;
  NVIC_InitTypeDef NVIC_InitStruct;

  // enable the peripherals we‘re going to use
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

  // Usart1 Tx is on GPIOB pin 6 as an alternative function
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOB, &GPIO_InitStruct);

  // Connect pin 6 to the USART
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);

  // fill in the interrupt configuration
  NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStruct);

  // init the USART to 8:N:1 at 9600 baud as specified in the
  // TTL data sheet
  USART_InitStruct.USART_BaudRate = 9600;
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;
  USART_InitStruct.USART_StopBits = USART_StopBits_1;
  USART_InitStruct.USART_Parity = USART_Parity_No;
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStruct.USART_Mode = USART_Mode_Tx;
  USART_Init(USART1, &USART_InitStruct);

  // Enable USART1 peripheral
  USART_Cmd(USART1, ENABLE);

  // ensure USART1 interrupts are off until we have data
  USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

  // prepare the buffer
  TTL_Buffer_Init();
}

3. 实现中断处理方法读消息

/* Public Methods -----------------------------------------------------------*/

/*
* Handles all interrupts for USART1.
*/
void USART1_IRQHandler(void)
{
  // is this interrupt telling us that we can send a new character?
  if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET) {
    // is there something for us to read?
    if (TTL_Buffer_IsEmpty()) {
      // no, disable the interrupt
      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
    } else {
      // yes, get the next character from the buffer
      char c = 0x00;
      TTL_Buffer_Read(&c);
      // send it to the device
      USART_SendData(USART1, c);
    }
  }
}

4. 工具方法: 写消息, 反初始化(非必须)

注意在每次调用USART_SendData这个方法之后, 都需要阻塞判断 USART_FLAG_TC 是否为SET才能继续往下执行.

...
USART_SendData(USART1, *str++);
while( USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
...

例如

/* Public Methods -----------------------------------------------------------*/

void TTL_DeInit()
{
  // disable the interrupts
  USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
  // free the buffer
  TTL_Buffer_Free();
}
 
uint16_t TTL_IsBufferFull()
{
  return TTL_Buffer_IsFull();
}

uint16_t TTL_WriteMessage(char* text, uint16_t length)
{
  // index into the character array
  uint16_t i = 0;
  // return value
  uint16_t rv = TTL_WriteOk;

  while(length--) {
    USART_SendData(USART1, *text++);
    // USART_SendData(USART1,(uint16_t) *text++);
    // Loop until the end of transmission
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
  }
  // enable the interrupt to send the message
  USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

  return rv;
}

代码例子

这是一个完整的代码例子, 适用于STM32F103

#include "sys.h"
#include "usart.h"    
#include "delay.h"

u8 usart1_buf[100] = {0}, usart2_buf[100] = {0}, usart3_buf[100] = {0};
u16 index1 = 0, index2 = 0, index3 = 0, flag1 = 0, flag2 = 0, flag3 = 0;

void uart_init(u32 bound){
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  RCC_APB1PeriphClockCmd(
    RCC_APB1Periph_USART2 | RCC_APB1Periph_USART3, ENABLE);

  //使能USART1,GPIOA时钟
  RCC_APB2PeriphClockCmd(
    RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);

  /*************UART1********************/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);          //初始化GPIOA.9

  //USART1_RX   GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;           //PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);       //初始化GPIOA.10  

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器

  USART_InitStructure.USART_BaudRate = bound;//串口波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
  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_Rx | USART_Mode_Tx; //收发模式

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

  /***************UART2******************/    
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);          //初始化GPIOA.2

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);          //初始化GPIOA.3  

  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器

  USART_InitStructure.USART_BaudRate = bound;//串口波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
  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_Rx | USART_Mode_Tx; //收发模式

  USART_Init(USART2, &USART_InitStructure); //初始化串口2
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART2, ENABLE);                    //使能串口2 

  /****************UART3***********************/  

  //USART3_TX   GPIOB.10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;        //PB.10
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure);            //初始化GPIOB.10

  //USART3_RX   GPIOB.11
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;        //PB11
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);            //初始化GPIOB.11

  //Usart3 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;  //抢占优先级4
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;       //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    //IRQ通道使能
  NVIC_Init(&NVIC_InitStructure);                //根据指定的参数初始化VIC寄存器

  USART_InitStructure.USART_BaudRate = 115200;      //串口波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
  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_Rx | USART_Mode_Tx; //收发模式

  USART_Init(USART3, &USART_InitStructure);      //初始化串口3
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); //开启串口接受中断
  USART_Cmd(USART3, ENABLE);
}

/**
  每个字节一个中断, 这里用0x0a作为一条消息读取结束
*/
void USART1_IRQHandler(void)
{
  u16 code;
  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {   
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);//Removal of receiving interrupt flag
    code = USART_ReceiveData(USART1);
    usart1_buf[index1] = code;
    index1++;       
    if(code == 0x0a) {
        index1 = 0;
        flag1 = 1;
    }
  }    
}

void USART2_IRQHandler(void)
{
  u16 code;
  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {   
    USART_ClearITPendingBit(USART2, USART_IT_RXNE);
    code=USART_ReceiveData(USART2);
    usart2_buf[index2] = code;
    index2++;
    if(code == 0x0a) {
        index2 = 0;
        flag2 = 1;
    }
  }
}

void USART3_IRQHandler(void)
{
  u16 code;
  if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
    USART_ClearITPendingBit(USART3, USART_IT_RXNE);
    code = USART_ReceiveData(USART3);
    usart3_buf[index3] = code;
    index3++;
    if(code == 0x0a) {
        index3 = 0;
        flag3 = 1;
    }
  }
}

void USART1_Send(u8 *str)
{
  while(*str != 0x0a) {
    USART_GetFlagStatus(USART1, USART_FLAG_TC);
    USART_SendData(USART1, *str++);
    while( USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
  }
  USART_SendData(USART1, 0x0a);
}

void USART2_Send(u8 *str)
{
  while(*str != 0x0a) {
    USART_GetFlagStatus(USART2, USART_FLAG_TC);
    USART_SendData(USART2, *str++);
    while( USART_GetFlagStatus(USART2,USART_FLAG_TC) != SET);
  }
  USART_SendData(USART2, 0x0a);
}

void USART3_Send(u8 *str)
{
  while(*str != 0x0a) {
    USART_GetFlagStatus(USART3, USART_FLAG_TC);
    USART_SendData(USART3, *str++);
    while( USART_GetFlagStatus(USART3,USART_FLAG_TC) != SET);
  }
  USART_SendData(USART3, 0x0a);
}





/*******************main***********************/

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h" 
#include "buzzer.h"
#include "string.h"

int main(void)
{
  u8 Zigb_Head[]="ZigB:";
  u8 buf[100];
  delay_init();       
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
  uart_init(115200);  
  Buzzer_Init();
  LED_Init();              

  while(1) {
    if(flag2 == 1) {
      LED0=0;
      flag2=0; 
      USART3_Send(usart2_buf);
      memset(usart2_buf,0,sizeof(usart2_buf));
    } else if(flag3==1) {
      LED1=0;
      flag3=0;
      memcpy(buf,Zigb_Head,sizeof(Zigb_Head));
      strcat(buf,usart3_buf);
      USART2_Send(buf);
      memset(buf,0,sizeof(buf));
    }
    delay_ms(500);
    LED1=1; 
    LED0=1;
    delay_ms(500);
  }
}

参考

STM32的串口通信UART/TTL

原文:https://www.cnblogs.com/milton/p/14714164.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!