STM32 USART通信相关

233 阅读6分钟

内部通信接口相关操作

1.1 USART发送程序

  1. 端口信息

UART电路图.png 2. 初始化时钟和串口 USART1_Init void USART1_Init(u32 bound) 功能: 初始化UART相关端口 参数: bound:波特率,600,1200,2400,4800,9600,14400,19200,115200 返回值: 无

void USART1_Init(u32 bound){ //串口1初始化并启动
   //GPIO端口设置
   GPIO_InitTypeDef GPIO_InitStructure;
   USART_InitTypeDef USART_InitStructure;
   NVIC_InitTypeDef NVIC_InitStructure;	 
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
   //USART1_TX   PA.9
   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);  
   //USART1_RX	  PA.10
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
   GPIO_Init(GPIOA, &GPIO_InitStructure); 
   //Usart1 NVIC 配置
   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
   NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器 
   //USART 初始化设置
   USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
   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); //初始化串口
   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启ENABLE/关闭DISABLE中断
   USART_Cmd(USART1, ENABLE);                    //使能串口 
}
  1. 发送方法
    1. 方法1:
      1. 数据发送 USART_SendData void USART_SendData(USART_TypeDef* USARTx, u8 Data) 功能: 通过外设 USARTx 发送单个数据 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 Data: 待发送的数据(八位十六进制) 返回值: 无

      2. 检查发送完成标志位状态,防止数据冲突 USART_GetFlagStatus FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, u16 USART_FLAG) 功能: 检查指定的 USART 标志位设置与否 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 USART_FLAG:待检查的 USART 标志位

          USART_FLAG_CTS CTS标志位
          USART_FLAG_LBDLIN 中断检测标志位
          USART_FLAG_TXE 发送数据寄存器空标志位
          USART_FLAG_TC 发送完成标志位
          USART_FLAG_RXNE 接收数据寄存器非空标志位
          USART_FLAG_IDLE 空闲总线标志位
          USART_FLAG_ORE 溢出错误标志位
          USART_FLAG_NE 噪声错误标志位
          USART_FLAG_FE 帧错误标志位
          USART_FLAG_PE 奇偶错误标志位
        

        返回值: USART_FLAG 的新状态(SET 或者 RESET)

    2. 方法2: printf发送字符串 功能: 单一串口发送字符串,同一时间只能使用在一个串口上
    3. 方法3: USART1_printf 功能: 自定义函数,多串口发送字符串,可同一时间多个串口使用
      void USART1_printf (char *fmt, ...){ 
      char buffer[USART1_REC_LEN+1];  // 数据长度
      u8 i = 0;	
      va_list arg_ptr;
      va_start(arg_ptr, fmt);  
      vsnprintf(buffer, USART1_REC_LEN+1, fmt, arg_ptr);
         while ((i < USART1_REC_LEN) && (i < strlen(buffer))){
         USART_SendData(USART1, (u8) buffer[i++]);
         while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); 
         }
       va_end(arg_ptr);
      }
      
    4. 相关概念
      1. 单引号引用ASCII码,例:'U'

1.2 USART接收程序

  1. 初始化时钟,串口
  2. 查询方式接收
    1. 关闭串口中断

    2. 监控接收数据标志位的状态,为0停止接收

    3. USART_GetFlagStatus FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, u16 USART_FLAG) 功能: 检查指定的 USART 标志位设置与否 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 USART_FLAG:待检查的 USART 标志位

           USART_FLAG_CTS CTS标志位
           USART_FLAG_LBDLIN 中断检测标志位
           USART_FLAG_TXE 发送数据寄存器空标志位
           USART_FLAG_TC 发送完成标志位
           USART_FLAG_RXNE 接收数据寄存器非空标志位
           USART_FLAG_IDLE 空闲总线标志位
           USART_FLAG_ORE 溢出错误标志位
           USART_FLAG_NE 噪声错误标志位
           USART_FLAG_FE 帧错误标志位
           USART_FLAG_PE 奇偶错误标志位
      

      返回值: USART_FLAG 的新状态(SET 或者 RESET)

    4. 接收数据 USART_ReceiveData u8 USART_ReceiveData(USART_TypeDef* USARTx) 功能: 返回 USARTx 最近接收到的数据 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 返回值: 接收到的字

  3. 中断方式接收(实时性高)
    1. 打开串口中断,串口在收到数据时跳到中断处理程序接收数据,接收完跳回主程序

    2. 在中断处理函数中设置接收程序

    3. 监控接收中断标志位的状态,为0停止接收 USART_GetITStatus ITStatus USART_GetITStatus(USART_TypeDef* USARTx, u16 USART_IT) 功能: 检查指定的 USART 中断发生与否 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 USART_IT:待检查的 USART 中断源

           USART_IT_PE 奇偶错误中断
           USART_IT_TXE 发送中断
           USART_IT_TC 发送完成中断
           USART_IT_RXNE 接收中断
           USART_IT_IDLE 空闲总线中断
           USART_IT_LBD LIN中断探测中断
           USART_IT_CTS CTS中断
           USART_IT_ORE 溢出错误中断
           USART_IT_NE 噪音错误中断
           USART_IT_FE 帧错误中断
      

      返回值: USART_IT 的新状态(SET 或者 RESET)

    4. 接收数据 USART_ReceiveData u8 USART_ReceiveData(USART_TypeDef* USARTx) 功能: 返回 USARTx 最近接收到的数据 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 返回值: 接收到的字

1.3 超级终端显示设置

  1. 超级终端转彩色显示 以"\033["开始以"m"结尾,以";"分隔,系统默认颜色"\033[0m"

    前景背景颜色
    3040黑色
    3141紅色
    3242綠色
    3343黃色
    3444藍色
    3545紫紅色
    3646青藍色
    3747白色
    编号效果
    0终端默认设置(黑底白字)
    1高亮显示
    4使用下划线
    5闪烁
    7反白显示
    8不可见

1.4 超级终端串口控制程序

  1. PC端控制如下菜单效果:

    1y--开LED1灯 1n--关LED1灯 2y--开LED2灯 2n--关LED2灯 请输入控制指令,按回车键执行!

    菜单高亮显示,白色背景,黄色前景

  2. 初始化时钟,LED,串口

  3. 初始值设为菜单界面

  4. 打开中断接收方式

    1. 判断是否接收到数据,将收到的数据发送回PC端作为显示(数据以1y,1n,2y,2n加回车0x0d和换行符0x0a结尾)
    2. 创建16位无符号全局变量USART1_RX_STA辅助判断接收数据状态,收到回车高二位置1,收到换行符高1位置1,收到数据值加1
    3. 创建数组USART1_RX_BUF[]将接收到的数据(不含回车和换行符)从第0个元素开始保存进数组
    4. 判断接收数据是否为回车+换行符,是则USART1_RX_STA高一高二位均置1,结束接收
  5. 主函数判断接收数据并做相应处理,若只收到回车加换行符打印一次选择界面

  6. USART1_RX_STA函数高一二位置1,实现开机打印选择界面

//中断函数
void USART1_IRQHandler(void){ //串口1中断服务程序(固定的函数名不能修改)	
u8 Res;
//以下是字符串接收到USART_RX_BUF[]的程序,(USART_RX_STA&0x3FFF)是数据的长度(不包括回车)
//当(USART_RX_STA&0xC000)为真时表示数据接收完成,即超级终端里按下回车键。
//在主函数里写判断if(USART_RX_STA&0xC000),然后读USART_RX_BUF[]数组,读到0x0d 0x0a即是结束。
//注意在主函数处理完串口数据后,要将USART_RX_STA清0

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){  //接收中断(接收到的数据必须是0x0d 0x0a结尾)		
   Res =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
   printf("%c",Res); //把收到的数据以 a符号变量 发送回电脑		
   
   if((USART1_RX_STA&0x8000)==0){//判断USART1_RX_STA高一位是不是1
      if(USART1_RX_STA&0x4000){//判断USART1_RX_STA高二位是不是1				
         if(Res!=0x0a)USART1_RX_STA=0;//判断接收值Res不是换行符,USART1_RX_STA置零,接收错误重新开始
         else USART1_RX_STA|=0x8000;	//判断接收值Res是换行符USART1_RX_STA高一,二位置1,接收完成 
      }
else{ 			
      if(Res==0x0d)USART1_RX_STA|=0x4000;//判断接收值Res是回车,USART1_RX_STA高二位置1
      else{//判断接收值Res不是回车
         USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ; //将接收值Res放入数组第USART1_RX_STA&0X3FFF位
         USART1_RX_STA++;	//USART1_RX_STA数据长度计数加1
         if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据超过BUF长度,USART1_RX_STA置0重新开始接收	  
      }}}}}	
   
//主函数:
while(1){
   if(USART1_RX_STA&0xC000){ //如果标志位是0xC000表示收到数据串完成,可以处理。
      if((USART1_RX_STA&0x3FFF)==0){ //单独的回车键再显示一次欢迎词
         printf("\033[1;47;33m\r\n"); //设置颜色(参考超级终端使用)
         printf(" 1y--开LED1灯      1n--关LED1灯 \r\n");
         printf(" 2y--开LED2灯      2n--关LED2灯 \r\n");
         printf(" 请输入控制指令,按回车键执行! \033[0m\r\n");
      }else if((USART1_RX_STA&0x3FFF)==2 && USART1_RX_BUF[0]=='1' && USART1_RX_BUF[1]=='y'){ //判断数据是不是2个,第一个数据是不是“1”,第二个是不是“y”
         GPIO_SetBits(LEDPORT,LED1); //LED灯都为高电平(1)
         printf("1y -- LED1灯已经点亮!\r\n"444441);
      }else if((USART1_RX_STA&0x3FFF)==2 && USART1_RX_BUF[0]=='1' && USART1_RX_BUF[1]=='n'){
         GPIO_ResetBits(LEDPORT,LED1); ////LED灯都为低电平(0)
         printf("1n -- LED1灯已经熄灭!\r\n");
      }else if((USART1_RX_STA&0x3FFF)==2 && USART1_RX_BUF[0]=='2' && USART1_RX_BUF[1]=='y'){
         GPIO_SetBits(LEDPORT,LED2); //LED灯都为高电平(1)
         printf("2y -- LED2灯已经点亮!\r\n");
      }else if((USART1_RX_STA&0x3FFF)==2 && USART1_RX_BUF[0]=='2' && USART1_RX_BUF[1]=='n'){
         GPIO_ResetBits(LEDPORT,LED2); ////LED灯都为低电平(0)
         printf("2n -- LED2灯已经熄灭!\r\n");
      }else{ //如果以上都不是,即是错误的指令。
         printf("指令错误!\r\n"); 
      }
      USART1_RX_STA=0; //将串口数据标志位清0
}
} 
  1. 相关概念
    1. 全局变量extern 全局变量在函数任意位置都可以调用,但是固定占用RAM空间不宜过多使用,在.c文件定义全局变量,在.h文件extern声明即可使用
    2. 位运算:
      1. &按位与 两个位都为1时,结果才为1
      2. |按位或 两个位都为0时,结果才为0
      3. ~按位取反 两个位相同为0,相异为1
      4. ^按位异或 0变1,1变0
      5. << 左移 各二进位全部左移若干位,高位丢弃,低位补0
      6. >> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,右移补1