IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> stm32学习笔记(五)—— USART串口 -> 正文阅读

[嵌入式]stm32学习笔记(五)—— USART串口

目录

一. 串口介绍

1.1 物理层

?1.2 协议层

1.2.1 波特率和比特率

1.2.2 起始和结束

1.2.3 有效数据

1.2.4 校验位

二. 串口功能讲解

三. 寄存器介绍

3.1 状态寄存器?

3.2 数据寄存器

?3.3 波特率寄存器

3.4 三个控制寄存器

四. 应用函数

4.1 初始化结构体

4.2 初始化函数

4.3 应用函数

4.3.1 发送数据

4.3.2 接收数据

4.3.3 重定位printf和scanf函数


简单介绍一下串口,然后介绍了串口的初始化结构体、函数,还有一些有关串口的应用

一. 串口介绍

1.1 物理层

? ? ? ? 电平有两种,一个是RS232标准,一种是TTL标准。在嵌入式用的是TTL标准

?

?1.2 协议层

串口通信时,一个控制器的发送口TXD与另一个控制器的接收口RXD相连,一个控制器的接收口RXD与另一个控制器的发送口TXD相连,这样才能一个发一个收

1.2.1 波特率和比特率

????????波特率和比特率不是一个东西,波特率与码元相关,而比特率之和比特位数有关

1.2.2 起始和结束

? ? ? ? 通过寄存器设置,可以设置一个起始位和0.5、1、1.5、2个停止位

? ? ? ? 其中,起始位是一个低电平信号,停止位是高电平

1.2.3 有效数据

? ? ? ? 首先来了一个起始位,接着就是n位数据位,数据位的具体位数可以通过寄存器调节

1.2.4 校验位

? ? ? ? 一般自带的有奇偶校验位,但是我现在打工的地方用的CRC校验比较多,不用自带的奇偶校验。

? ? ? ? 关于奇偶校验,指的是,通过在数据位后面多放一个位用来加上前面数据中“1”的个数来使1的总数是奇还是偶。比如选定了奇校验,而数据中有3个1,那么这个位写0就好了;如果前面有四个1,那这个位就会变成1,这时1的总数是五个,为奇。

二. 串口功能讲解

? ? ? ? 一般异步串行通信用的比较多,就介绍这种,异步串行用到的引脚只有TX、RX两个。SCLK用于同步发送时的时钟信号,IRDA_OUT和IRDA_IN是在IRDA模式下用到的,CTS和RTS时用于流控制,当串口准备好接收新数据时nRST变低,接收寄存器满时,nRST变高;串口发送时,监测nCTS,如果是低,就可以发送下一帧数据,如果是高就不发送下一帧。这两个引脚用在硬件流控制中

? ? ? ? ?串口向外发送数据时,需要把数据写到发送数据寄存器里,然后数据会被传送到发送移位寄存器中,然后被移位寄存器一位移位移出来送到外面。接收同理,只不过是反过来的过程,接收时,接收移位寄存器把数据一位一位移进来然后给到接收数据寄存器

? ? ? ? 其中,发送数据寄存器和接收数据寄存器在操作的时候是同一个名字,都叫USART_DR,但是物理意义上是两个寄存器

? ? ? ? 发送时,先发送低位

三. 寄存器介绍

3.1 状态寄存器

?

?

?

其中,要注意,

TXE发送数据寄存器空 (Transmit data register empty) :当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1 寄存器中的TXEIE为1,则产生中断。对USART_DR的写操作,将该位清零。 0:数据还没有被转移到移位寄存器; 1:数据已经被转移到移位寄存器。 注意:单缓冲器传输中使用该位。即,一帧数据发送完成时,TXE位自动置1,向USART_DR数据寄存器写数据时自动清零。

TC:发送完成 (Transmission complete) 当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置’1’。如果USART_CR1中的 TCIE为’1’,则产生中断。由软件序列清除该位(先读USART_SR,然后写入USART_DR)。TC 位也可以通过写入’0’来清除,只有在多缓存通讯中才推荐这种清除程序。 0:发送还未完成; 1:发送完成。功能和TXE差不多

RXNE:读数据寄存器非空 (Read data register not empty) 当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位被硬件置位。如果 USART_CR1寄存器中的RXNEIE为1,则产生中断。对USART_DR的读操作可以将该位清零。RXNE位也可以通过写入0来清除,只有在多缓存通讯中才推荐这种清除程序。 0:数据没有收到; 1:收到数据,可以读出。即,一帧数据接收完成,RXNE自动置1,读USART_DR数据寄存器时自动清零

3.2 数据寄存器

正如前文所说的,这个寄存器实际上是由两个寄存器组成一个是发送的数据的寄存器,一个是接收的数据的寄存器

?3.3 波特率寄存器

?用来设置波特率,可以参考参考手册的27.3.4的公式

比如:想要设置波特率为9600时,我们已经知道我们的频率fck,fck是给外设的时钟(PCLK1用于USART2、3、4、5,PCLK2用于USART1),根据之前的时钟图,就知道这里的fck是72MHz,所以可以计算得到USARTDIV = 468.75,所以整数部分时468,而小数部分用余数将其表示出来,即16*0.75=12;最后把他们填写到波特率寄存器中,DIV_Mantissa[11:0]用来存整数,DIV_Fraction[3:0]用来存余数,所以这个寄存器写入的是0x1D4C,注意当余数是个小数时,将其取整到最接近的整数

?

3.4 三个控制寄存器

这个寄存器主要控制了中断使能,接收发送和串口的使能,字长,校验方式等。

在使用时,要注意使能第十三位的串口使能开关,这个开关开启了串口才会有作用,关于它有一个单独的使能函数。其次还有接收、发送的使能,这两个使能在串口的初始化结构体中的mode项中选择。

?要关注第13 12两个位,用来设置停止位的位数;此外,同步通信时,CPOL控制CLK在空闲时候的电平是高还是低,CPHA决定在单数还是双数的边沿触发数据接收,二者相互配合就能决定初始的时钟状态和上/下边沿接收数据

第三个寄存器用的少不看了

四. 应用函数

4.1 初始化结构体

?结构体的定义在 stm32f10x_usart.h文件中

库函数编程的一个好处就是初始化结构体等等各种东西的选项在其.h文件中都有对应的宏定义,我们从里面找就可以了。

第一项波特率,这里直接填预期的波特率就可以了,函数内部会帮我们计算具体值。然后是选传输的有效数据位长度,停止位位数,奇偶校验位,硬件流控制。其中模式选择就是刚才上面使能中所说到的接收发送使能位。

4.2 初始化函数

//串口的中断配置,和之前的中断都是一样的,选中断通道、
//中断通道使能、分组和设置抢断优先级子优先级
static void NVIC_Config(void)
{
  NVIC_InitTypeDef  NVIC_InitStruct;
  
  //初始化中断
  NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  
  //设置中断分组
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  NVIC_Init(&NVIC_InitStruct);
}

//我的板子用到的是串口1
void USART1_Config(void)
{
  USART_InitTypeDef USART1_InitStructure;
  GPIO_InitTypeDef  USART1_TX_Structure;
  GPIO_InitTypeDef  USART1_RX_Structure;
  
  //万年不变,设置前先开启相关时钟
  //使能串口时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);  
  //使能GPIO时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  
  //初始化GPIO A9,设置为TX口,复用推挽输出!!
  USART1_TX_Structure.GPIO_Mode = GPIO_Mode_AF_PP;
  USART1_TX_Structure.GPIO_Pin = GPIO_Pin_9;
  USART1_TX_Structure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &USART1_TX_Structure);
  
  //初始化GPIO A10,设置为RX口,浮空输入!!
  USART1_RX_Structure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  USART1_RX_Structure.GPIO_Pin = GPIO_Pin_10;
  GPIO_Init(GPIOA, &USART1_RX_Structure);
  

  //串口初始化
    //设置波特率
  USART1_InitStructure.USART_BaudRate = 115200;
    //不用硬件控制流
  USART1_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    //设置模式,这里我们又要接收又要发送所以用 或
  USART1_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    //不要奇偶校验
  USART1_InitStructure.USART_Parity = USART_Parity_No;
    //1个停止位
  USART1_InitStructure.USART_StopBits = USART_StopBits_1;
    //8个有效数据位
  USART1_InitStructure.USART_WordLength = USART_WordLength_8b;
  
  //串口初始化
  USART_Init(USART1, &USART1_InitStructure);
  
  //使能接收中断
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  
  NVIC_Config();
  
  //使能串口1!!!!!!!!这个就是刚才介绍的控制寄存器1的第13位,串口的使能位
  USART_Cmd(USART1, ENABLE);
  
}

4.3 应用函数

4.3.1 发送数据

//发送单个字节,用来供后面发送整个消息循环调用
//输入参数中
//pUSARTx:是串口通道,在库函数里可以找到
//data:需要发送的数据

void USART_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
    //库函数,发送数据
  USART_SendData(pUSARTx, data);
    //等待数据被转移到发送移位寄存器中
  while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}



//正式发送整个信息
//信息存在uint8_t的数组中
void USART_SendMessage(USART_TypeDef* pUSARTx, uint8_t* group)
{
  uint8_t i = 0;
  do
  {
    USART_SendByte(pUSARTx, group[i]);
    i++;
  }
    //发送到数组的最后一个时结束发送
  while(group[i] != '\0');
}

4.3.2 接收数据

? ? ? ? 这里就放一个最简单的接收数据函数,接收数据这个任务是由接收中断来完成的,然后把数据从接收数据寄存器移到外面自己定义的数组里面。每接收到八位数据,就进入中断存一次

//定义两个全局变量,一个是存接受的数据,一个是定位
uint8_t Rev_Buffer[50];
uint8_t index = 0;


void USART1_IRQHandler(void)
{
    Rev_Buffer[index] = (uint8_t)USART_ReceiveData(USART1);
    index++;
}

? ? ? ? 在一般使用中,可以用这种方式来通过串口来给单片机发送数据,单片机把数据存下来,然后去到数据处理函数中,通过比对接收到的数据和我们事先定义好的命令,从而完成用电脑或其他设备通过串口向单片机发送控制命令来完成特定的工作。但是需要注意,在储存过程中,index这个值需要在合适的时候清零,方便下次发送数据时储存下一个命令。

? ? ? ? 这里就简单展示一下他的作用

?

4.3.3 重定位printf和scanf函数

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
    //等待先前数据传输到移位寄存器
    while( !(USART1->SR & (1 << 7)) );
    //发送字符
    USART_SendData(USART1, (uint8_t) ch);
    return ch;
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(USART1);
}

? ? ? ? 注意,在用到重定位用串口发送接收数据的时候要把keil里面的mirlib选项勾上

?

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-02 11:32:57  更:2021-09-02 11:34:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:42:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码