5.USART异步串行口输入输出(轮询模式)

  学习是一个简单的过程,只要有善于发掘的眼睛,总能学到新知识,然而如何坚持不懈的学习却很困难,对我亦如此,生活中有太多的诱惑,最后只想说一句勿忘初心。闲话不多扯,本篇讲诉的是异步串行口的输入输出,串口在外设中属于比较简单的通讯模式,但是在大型项目调试中又十分重要,理解该外设模块对于以后的通讯协议学习以及软件调试都有重要意义。

  通讯协议是指双方实体完成通信或服务所必须遵循的规则和约定,对于串口来说,包含波特率,数据位长度,停止位和数据校验位,当stm32芯片和客户端具有相同的协议约定时即能够正确的接收数据,因此串口外设的配置正是这些参数的设定。通过前面章节的学习,以USART1为例,在外设设置之前,我们应该有大致流程:

1. 串口外设外设和其占用的GPIO端口都要配置,且占用的GPIO端口为PA9(USART1_TX), PA10(USART1_RX).

2. 外设对应时钟都要配置,且要在初始化外设和GPIO端口配置之前

3. USART外设的配置主要是协议相关参数配置

串口外设配置

至于GPIO端口配置的参数参考<stm32F系列微控制器参考手册>(以后以手册简称)110页表21如下图

至于外设所在时钟区域,请参考RCC章节,如此外设的初始化如下:

头文件定义:

#define RCC_USART1           RCC_APB2Periph_GPIOA                                   |RCC_APB2Periph_USART1                                 |RCC_APB2Periph_AFIO
#define USART1_RX            GPIOA
#define USART1_TX            GPIOA
#define USART1_RX_Pin       GPIO_Pin_10
#define USART1_TX_Pin        GPIO_Pin_9

初始化代码:

  USART_InitTypeDef USART_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_DeInit(USART1);

  RCC_APB2PeriphClockCmd(RCC_USART1, ENABLE);            

  GPIO_InitStructure.GPIO_Pin = USART1_TX_Pin;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 //配置串口1输出端为复用推挽输出
  GPIO_Init(USART1_TX,&GPIO_InitStructure);    

  GPIO_InitStructure.GPIO_Pin = USART1_RX_Pin;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;           //配置串口1输入端为浮空输入
  GPIO_Init(USART1_RX, &GPIO_InitStructure);

  USART_InitStructure.USART_BaudRate = 115200;                    //设置串口波特率为9600
  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; //不采用硬件流控制
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //串口1启动输入输出

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

如此,便完成了外设的初始化。

这里有几个知识点要讲:

1.波特率  每秒发送的bit个数。对于一定长度的数据,在已知配置的情况下传输时间计算:

(以2k数据b,每帧8位数据,1位停止位,波特率9600,传输完成花费时间)

T = 2*1024*(8+1)/9600*8 = 0.24s

虽然用库函数可以直接设置波特率,但stm32的波特率如何通过寄存器计算还是很重要的,参考公式配置USART->BRR(手册542页):  

公式:

其中fck为串口所在区域外设时钟,如USART即为PCLK2时钟,USARTDIV即为要设置参数:

以波特率115200,PCLK等于系统时钟SYSTICk(48MHZ)算,USARTDIV设置为48M/(16*115200),转成二进制为0x1a0

2. 奇偶校验位

因为奇偶校验位的参与,接收到的数据帧有以下四种格式:

因此客户端接收时也要数据位要设定为实际数据长度,不然接收到数据会是乱码。

3. 硬件流控制

用于数据流控制,通讯的双方由此交换是否停止后继续接收信息,避免因处理数据速度问题而出现的缓存溢出,导致数据的丢失

 CTS只有CTS输入信号有效(低电平)时才能发送数据。如果在数据传输的过程中,CTS信号变成无效,那么发完这个数据后,传输就停止下来。如果当CTS为无效时,向数据寄   存器里写数据,则要等到CTS有效时才会发送这个数据。

RTS只有接收缓冲区内有空余的空间时才请求下一个数据。当前数据发送完成后,发送操作就需要暂停下来。如果可以接收数据了,将RTS输出置为有效(拉至低电平)。

ps:本例中没有使用,具体详情参考手册537页

串口输入输出实现

串口的输出是通过printf函数的,其包含在stdio.h头文件内部。此外printf还需要retarget处理,具体代码如下:

retarget.h头文件添加:

  #ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (
 option LD Linker->Libraries->Small printf
     set to ‘Yes‘) calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  #else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  #endif /* __GNUC__ */

retarget.c文件添加:

PUTCHAR_PROTOTYPE
{
  /*将1字节数据发往串口寄存器 */
  USART_SendData(USART1, (uint8_t) ch);  

  /*等待传输结束*/
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
  {}

  return ch;
}

之后就可以用printf函数发送数据了,至于接收则采用缓存模式,将接受数据存储到数组中,接收到\n时结束并发送:

u8 i = 0;
do
{
   while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
   {
   }
   USART_STORE[i] = USART1->DR;
   if(USART_STORE[i] == ‘\n‘)
   {
      break;
   }
   i++;
   if(i >= USART_ISL)
   {
     i = 0;
     printf("you input is overlength");
     break;
   }
 }while(1);

 if(i < USART_ISL)
 {
    //printf("you input is ");
    printf("\n%s",USART_STORE);
 }

如此就完成了USART外设的配置和输入输出轮询实现。

具体代码参考:http://files.cnblogs.com/files/zc110747/2.1-USART%28%E8%BD%AE%E8%AF%A2%E6%A8%A1%E5%BC%8F%29.7z

时间: 2024-10-11 05:47:57

5.USART异步串行口输入输出(轮询模式)的相关文章

十天学会单片机Day4串行口通信

并行与串行基本通信方式 1.并行通信方式 通常是将数据字节的各位用多条数据线同时进行传送. 并行通信控制简单.传输速度快:由于传输线较多,长距离传送时成本高且接收方的各位同时接收存在困难. 2.串行通信方式 是将数据字节分成一位一位的形式在一条传输线上逐个地传送. 串行通信传输线少,长距离传送时成本低,且可以利用电话网等现成的设备,但数据的传送控制比并行通信复杂. 3.异步串行通信方式 异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程.为使双方的收发协调,要求发送和接收设备

单片机串行口介绍

介绍 串行口是单片机与外界进行信息交换的工具,8051单片机的通信方式有两种: 并行通信:数据的各位同时发送或接收.       串行通信:数据一位一位次序发送或接收. 串行通信的方式 异步通信 用一个起始位0表示字符的开始,用停止位1表示字符的结束,中间夹着8个数据位,字符能一个接一个传送 CPU与外设之间必须有字符格式和波特率两项规定 字符格式规定能使双方把0和1串理解成同一种意义,原则上自由制定,通用角度使用标准如ASCII 波特率即数据传输速率,每秒传送的二进制位数,如120字符/s,每

使用CreateFile()打开COM10及以上串行口

程序调试时发现,使用CreateFile()打开COM4时正常,打开COM10时却总是失败.这两个端口均为虚拟COM口,通过蓝牙仿真串口完成数据收发,除了命名不同外,本质上并无任何不同. 而MSDN上对使用CreateFile()打开设备函数却失败返回并无详细解释,百思不得其解.上网百度一下找到了相关资料,原来是: Win32 API函数CreateFile()除了可打开普通文件外,还可以打开设备,比如可用于打开串口,获得串口句柄. 使用CreateFile()函数打开串口时文件共享模式应设置为

同步,异步,串行队列,并发队列,全局队列,主队列等概念的总结

同步,异步,串行队列,并发队列,全局队列,主队列等概念的总结 在GCD函数中, 我们常常碰到同步,异步,串行队列,并发队列,全局队列,主队列等概念,而这些概念又常常组合在一起, 十分头疼, 这篇文章就来梳理一下这些烦人的概念. 不想看长篇大论的, 直接看文章末尾的表格即可! 在此之前, GCD中还涉及到两个十分重要的概念, 就是任务和队列 任务(Task): 你需要执行的操作 队列(Queue): 存放任务的容器 GCD中两个重要的函数, 一个同步执行, 一个异步执行 dispatch_asyn

演示STC89xx系列单片机串行口功能 (8-bit/9-bit)

1 /*------------------------------------------------------------------------------------*/ 2 /* --- STC MCU Limited ---------------- ---------------------------------------*/ 3 /* ---演示STC89xx系列单片机串行口功能 (8-bit/9-bit) ----------------*/ 4 /* --- Mobil

(九)串行口方式0 拓展并行输出端口 02 74LS164芯片

1.先讲解74LS164 移位芯片: 74HC164.74HCT164 是 8 位边沿触发式移位寄存器,串行输入数据,然后并行输出. 数据通过两个输入端(DSA 或 DSB)之一串行输入:任一输入端可以用作高电平使能端,控制另一输入端的数据输入.两个输入端或者连接在一起,或者把不用的输入端接高电平,一定不要悬空. 时钟 (CP) 每次由低变高时,数据右移一位,输入到 Q0, Q0 是两个数据输入端(DSA和 DSB)的逻辑与,它将上升时钟沿之前保持一个建立时间的长度. 主复位 (MR) 输入端上

iOS多线程——同步异步串行并行

串行并行异步同步的概念很容易让人混淆,关于这几个概念我在第一篇GCD中有解释,但是还不够清晰,所以这里重写一篇博客专门对这几个概念进行区分: 先说一下队列和任务: (1)队列分为串行和并行,任务的执行分为同步和异步,异步是多线程的代名词,异步在实际引用中会开启新的线程,执行耗时操作. (2)队列只是负责任务的调度,而不负责任务的执行,任务是在线程中执行. 以上两点对了解串行.并行.同步.异步非常重要! 再说一下队列和任务的特点: (1)串行队列:任务按照顺序被调度,前一个任务不执行完毕,队列不会

【iOS开发-91】GCD的同步异步串行并行、NSOperation和NSOperationQueue一级用dispatch_once实现单例(转载)

(1)GCD实现的同步异步.串行并行. ——同步sync应用场景:用户登录,利用阻塞 ——串行异步应用场景:下载等耗时间的任务 /** * 因为是异步,所以开通了子线程,但是因为是串行队列,所以只需要开通1个子线程(2),它们在子线程中顺序执行.最常用. */ -(void)gcdDemo1{ dispatch_queue_t q1=dispatch_queue_create("com.hellocation.gcdDemo", DISPATCH_QUEUE_SERIAL); for

GCD的同步异步串行并行、NSOperation和NSOperationQueue一级用dispatch_once实现单例

转:http://www.tuicool.com/articles/NVVnMn (1)GCD实现的同步异步.串行并行. ——同步sync应用场景:用户登录,利用阻塞 ——串行异步应用场景:下载等耗时间的任务 /** * 因为是异步,所以开通了子线程,但是因为是串行队列,所以只需要开通1个子线程(2),它们在子线程中顺序执行.最常用. */ -(void)gcdDemo1{ dispatch_queue_t q1=dispatch_queue_create("com.hellocation.gc