打印

百为STM32开发板教程之三——USART串口通信

[复制链接]
15225|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xi_liang|  楼主 | 2013-7-19 15:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
百为STM32开发板教程之三——USART串口通信

一、简介
STM32F103ZET6有3个USART(通用同步和异步收发器) + 2个UART(通用异步收发器)
分别是USART1,USART2,USART3
和UART4,UART5

二、USART和UART有什么区别呢?
当进行异步通信时,这两者是没有区别的。区别在于USART比UART多了同步通信功能,同步通信需要STM32提供时钟来同步的,
这个同步通信功能可以把USART当做SPI来用,比如用USART来驱动SPI设备。同步通信的连接示例图:


其中RX,TX,SCLK引脚的定义,在数据手册上都可以找到:百为stm32开发板光盘\芯片数据手册\数据手册STM32F103xC STM32F103xD STM32F103xE.pdf

这个区别在初学STM32的时候我们不需要去深入研究,只要知道USART有很多功能,除了全双工异步通信之外,还包括支持同步通信和单线半双工通信,支持LIN(局部互连网),智能卡协议和IrDA红外通信,以及调制解调器(CTS/RTS)等操作。

三、数据通信格式
我们用得最多的是全双工异步通信功能,下面我们来研究下怎么通过串口1(USART1)来收发信息,和printf功能的实现。

通常串口通信的数据格式如下图:


我们需要设置的数据有通信速率,数据字长,奇偶检验位,停止位。一个典型的设置是115200波特率,8位数据,无奇偶校验,1位停止位。
这个设置在固件函数库里面,我们是通过设置USART_InitStructure结构体,然后调用USART_Init函数来实现的:

  USART_InitStructure.USART_BaudRate = 115200;                                    //设置通信波特率为115200
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;     //设置通信数据格式为8位数据
  USART_InitStructure.USART_StopBits = USART_StopBits_1;                     //设置停止位为1位
  USART_InitStructure.USART_Parity = USART_Parity_No ;                         //设置为无奇偶校验
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //设置为无硬件流控制,即无CTS/RTS控制
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  //设置发送使能,接收使能
  
  USART_Init(USART1, &USART_InitStructure);  //调用USART_Init,把上面的参数分别设置进USART的控制寄存器USART1->CR1,USART1->CR2,USART1->CR3

  USART_Cmd(USART1, ENABLE);  //使能串口

大家发现,在2.0固件库的USART例程里并没有看到USART1,因为是它用USARTx宏代替的,
其中USARTx是platform_config.h里定义的,大概是这个样子:
#ifdef USE_USART1
  #define  USARTx                                USART1
  #define  GPIOx                                   GPIOA
  #define  RCC_APB2Periph_GPIOx       RCC_APB2Periph_GPIOA
  #define  GPIO_RxPin                          GPIO_Pin_10
  #define  GPIO_TxPin                          GPIO_Pin_9
#endif

只有定义了USE_USART1,上面的#ifdef USE_USART1和#endif之间的内容才会被编译,所以在platform_config.h里也需要定义USE_USART1:
#define USE_USART1

这里GPIO_Pin_9是串口1的发送引脚,GPIO_Pin_10是串口1的接收引脚,也可以从百为STM32开发板的电路图上看出来:


四、串口引脚配置
上面USART_Init函数配置了USART1的数据通信格式,但串口能工作的前提是需要配置相应的TX,RX的引脚,这个是通过GPIO_Configuration函数来配置的:
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);    //打开USART1时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  //打开AFIO时钟
  /* 配置 USARTx_Tx 为复用推挽输出 */
  GPIO_InitStructure.GPIO_Pin = GPIO_TxPin;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOx, &GPIO_InitStructure);
  /* 配置 USARTx_Rx 为输入悬空 */
  GPIO_InitStructure.GPIO_Pin = GPIO_RxPin;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOx, &GPIO_InitStructure);
}

五、收发数据
配置好USART1使用的引脚,数据通信格式,下面就可以收发数据了,
USART_GetFlagStatus函数可以读取收发状态等,读取状态标志可以是以下几个:


发送数据示例:
USART_SendData(USART1, 'a');  //发送一个字符a

接收数据示例:
u16 RxData;
RxData = USART_ReceiveData(USART1);  //从USART1接收数据到RxData变量

下面是串口通信printf程序里的主要功能,上电打印一串信息,把接收到的数据回显到PC上:
/* 用printf打印一串信息到PC的超级终端或串口调试软件上 */
  printf("\n\rUSART Printf Example: retarget the C library printf function to the USART\n\r");
  while (1)
  {
       if(USART_GetFlagStatus(USARTx,USART_FLAG_RXNE)==SET)  //判断是否有数据要接收
      {  
       i = USART_ReceiveData(USARTx);  //接收数据
       printf("%c\n\r",i&0xff);  //回显到PC的超级终端或串口调试软件上
      }
  }

六、printf的实现
上面的printf是怎么实现的呢,这个是C标准库里定义的函数,我们是怎样把它的输出重定向到串口的呢?

我们知道printf是调用fputc函数来打印的,所以我们只要把fputc函数重定义就可以了:
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

PUTCHAR_PROTOTYPE
{
  /* 调用USARTx发送一个字符*/
  USART_SendData(USARTx, (u8) ch);
  /* 等待发送完成 */
  while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET)
  {
  }
  return ch;
}

另外还要加上头文件
#include "stdio.h"

还要注意的是,在工程里要勾上USE MicroLIB

沙发
媛望| | 2014-4-14 17:23 | 只看该作者
想问一下,现有STM32芯片与指纹模块通过串口通信,指纹模块单独供电,那么RX,TX引脚设置什么输入与输出

使用特权

评论回复
板凳
xi_liang|  楼主 | 2014-4-16 14:49 | 只看该作者
媛望 发表于 2014-4-14 17:23
想问一下,现有STM32芯片与指纹模块通过串口通信,指纹模块单独供电,那么RX,TX引脚设置什么输入与输出 ...

按照这个设置就可以了
/* 配置 USARTx_Tx 为复用推挽输出 */
  GPIO_InitStructure.GPIO_Pin = GPIO_TxPin;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOx, &GPIO_InitStructure);
  /* 配置 USARTx_Rx 为输入悬空 */
  GPIO_InitStructure.GPIO_Pin = GPIO_RxPin;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOx, &GPIO_InitStructure);

使用特权

评论回复
地板
媛望| | 2014-4-17 16:41 | 只看该作者
想请教一个问题,最近在一个小工程中,用STM32F103c8t6芯片与一指纹模块通信,用的是串口3,用串口调试小助手,发现根本发不来数据,怎么回事啊?我的串口配置代码如下:
void InitUart()//初始化配置
{
  NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

USART_InitTypeDef USART_InitStructure;
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_Rx | USART_Mode_Tx;
  USART_Init(USART3, &USART_InitStructure);
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
  USART_ITConfig(USART3, USART_IT_TXE, DISABLE);
  USART_Cmd(USART3, ENABLE);
}

void USART3_SendByte(unsigned char temp)//发送一个字节
{
    USART_SendData(USART3, temp);
    while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
}

unsigned char USART3_ReceivByte()//接收一个字节
{
    unsigned char recev;
while(USART_GetFlagStatus(USART3, USART_FLAG_RXNE) == RESET);
    recev = USART_ReceiveData(USART3);
return recev;
}

主函数里
int main()
{
   SystemInit();
   InitUart();

   unsigned char i;
    for(i=0;i<6;i++) //发送包头
       USART3_SendByte(FM_Pack_Head[i]);//FM_Pack_Head[]前面是有定义的
    for(i=0;i<10;i++)
      USART3_SendByte(FM_Paswd_Vtfy[i]);
    for(i=0;i<12;i++)//读回应答信息
  dat[i]=USART3_ReceivByte();
}


麻烦您看一下,谢谢了

使用特权

评论回复
5
xi_liang|  楼主 | 2014-4-18 11:09 | 只看该作者
媛望 发表于 2014-4-17 16:41
想请教一个问题,最近在一个小工程中,用STM32F103c8t6芯片与一指纹模块通信,用的是串口3,用串口调试小助 ...

两个问题:
1、串口3管脚是否有重映射
2、你这个串口接收是用中断方式的,中断服务程序是否有处理

使用特权

评论回复
6
小班儿| | 2014-11-27 10:08 | 只看该作者
正在搞USART,受教了!

使用特权

评论回复
7
IanLei| | 2016-6-24 18:42 | 只看该作者
dadwadsadfsafdfdsfsdgrsgrstgtrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddf

使用特权

评论回复
8
david_liang| | 2016-8-10 11:15 | 只看该作者
感谢楼主,受教了

使用特权

评论回复
9
arao和xiaomi| | 2017-3-15 23:12 | 只看该作者
学习中

使用特权

评论回复
10
arao和xiaomi| | 2017-3-15 23:14 | 只看该作者
媛望 发表于 2014-4-14 17:23
想问一下,现有STM32芯片与指纹模块通过串口通信,指纹模块单独供电,那么RX,TX引脚设置什么输入与输出 ...

我为什么看不了那个电路图呀

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:http://baiweijishu.taobao.com/ 百为STM32开发板 兼容官方STM3210E-EVAL开发板 WM-G-MR-09 WIFI开发板

41

主题

285

帖子

10

粉丝