您当前的位置: 首页 >  stm32

跋扈洋

暂无认证

  • 3浏览

    0关注

    221博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

STM32(七)-------串口通信

跋扈洋 发布时间:2022-04-22 16:37:39 ,浏览量:3

串口通信
  • 介绍
    • 数据格式
    • UART传输数据顺序
      • 发送数据过程
      • 数据接收过程
    • 硬件连接
  • 软件实现
    • USART初始化结构体详解
    • 串口通信实例
      • 非中断实现
      • 中断实现
      • 发送数据
      • 使用
  • 后续

介绍

串口(UART通用异步收发器,TTL)通讯是一种设备间的串行全双工通讯方式。由于UART是异步传输,没有传输同步时钟,为了保证数据的正确性,UART采用16倍数据波特率的时钟进行采样。

数据格式

起始位:先发出一个逻辑”0”的信号,表示传输数据的开始。 数据位:可以选择的值有5,6,7,8这四个值,可以传输这么多个值为0或者1的bit位。这个参数最好为8,因为如果此值为其他的值时当你传输的是ASCII值时一般解析肯定会出问题。理由很简单,一个ASCII字符值为8位,如果一帧的数据位为7,那么还有一位就是不确定的值,这样就会出错。 校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。 停止位:它是一帧数据的结束标志。可以是1bit、1.5bit、2bit的空闲电平。 空闲位:没有数据传输时线路上的电平状态。为逻辑1。

UART传输数据顺序

刚开始传输一个起始位,接着传输数据位,接着传输校验位(可不需要此位),最后传输停止位。这样一帧的数据就传输完了。接下来接着像这样一直传送。

发送数据过程

空闲状态,线路处于高电平;当收到发送指令后,拉低线路的一个数据位的时间T,接着数据按低位到高位依次发送,数据发送完毕后,接着发送奇偶校验位和停止位,一帧数据发送完成。

数据接收过程

空闲状态,线路处于高电平;当检测到线路的下降沿(高电平变为低电平)时说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕后,接着接收并比较奇偶校验位是否正确,如果正确则通知后续设备接收数据或存入缓冲。

硬件连接

UART的硬件连接比较简单,只需要两个设备的TXD和RXD相互反接,再将GND相连即可。

#mermaid-svg-5fAUhhxEgqJunPO5 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-5fAUhhxEgqJunPO5 .error-icon{fill:#552222;}#mermaid-svg-5fAUhhxEgqJunPO5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5fAUhhxEgqJunPO5 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-5fAUhhxEgqJunPO5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5fAUhhxEgqJunPO5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5fAUhhxEgqJunPO5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5fAUhhxEgqJunPO5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5fAUhhxEgqJunPO5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5fAUhhxEgqJunPO5 .marker.cross{stroke:#333333;}#mermaid-svg-5fAUhhxEgqJunPO5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5fAUhhxEgqJunPO5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5fAUhhxEgqJunPO5 .cluster-label text{fill:#333;}#mermaid-svg-5fAUhhxEgqJunPO5 .cluster-label span{color:#333;}#mermaid-svg-5fAUhhxEgqJunPO5 .label text,#mermaid-svg-5fAUhhxEgqJunPO5 span{fill:#333;color:#333;}#mermaid-svg-5fAUhhxEgqJunPO5 .node rect,#mermaid-svg-5fAUhhxEgqJunPO5 .node circle,#mermaid-svg-5fAUhhxEgqJunPO5 .node ellipse,#mermaid-svg-5fAUhhxEgqJunPO5 .node polygon,#mermaid-svg-5fAUhhxEgqJunPO5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5fAUhhxEgqJunPO5 .node .label{text-align:center;}#mermaid-svg-5fAUhhxEgqJunPO5 .node.clickable{cursor:pointer;}#mermaid-svg-5fAUhhxEgqJunPO5 .arrowheadPath{fill:#333333;}#mermaid-svg-5fAUhhxEgqJunPO5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5fAUhhxEgqJunPO5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5fAUhhxEgqJunPO5 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-5fAUhhxEgqJunPO5 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-5fAUhhxEgqJunPO5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5fAUhhxEgqJunPO5 .cluster text{fill:#333;}#mermaid-svg-5fAUhhxEgqJunPO5 .cluster span{color:#333;}#mermaid-svg-5fAUhhxEgqJunPO5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5fAUhhxEgqJunPO5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
TXD
RXD
RXD
TXD
GND
GND
软件实现 USART初始化结构体详解

标准库函数对每个外设都建立了一个初始化结构体,例如USART_InitTypeDef,结构体成员用于设置外设工作参数,并由外设初始化配置函数,比如USART_Init()调用,这些设定参数将会设置外设相应的寄存器。初始化结构体和初始化库函数配合使用是标准库精髓所在。初始化结构体定义在stm32f10x_usart.h文件中,初始化库函数定义在stm32f10x_usart.c。 USART初始化结构体

typedef struct
{
  uint32_t USART_BaudRate;  //波特率          
  uint16_t USART_WordLength;  //字长
  uint16_t USART_StopBits;  //停止位
  uint16_t USART_Parity;   //校验位  
  uint16_t USART_Mode;     //USART模式         
  uint16_t USART_HardwareFlowControl;//硬件流控制 
} USART_InitTypeDef;
  1. USART_BaudRate:设置波特率,一般设置为2400,9600,115200.标准库会根据设定值计算得到USARTDIV值,从而设置USART_BRR寄存器值。
  2. USART_WordLength:数据帧字长,可选8位或9位。它设置USART_CR1寄存器的M位的值。如果没有使能奇偶校验控制,一般设置8数据位。
  3. USART_StopBits; 停止位设置,可选0.5个,1个,1.5个,2个停止位,它设定USART_CR2寄存器的STOP【1:0】位的值,一般选择1个停止位。
  4. USART_StopBits:奇偶校验控制选择,可选USART_StopBits_No(无校验)、USART_StopBits_Even(偶校验)以及USART_StopBits_Odd(奇校验),它设定USART_CR1寄存器的PCE位和PS位的值。
  5. USART_Mode:USART模式选择,有USART_Mode_Rx和USART_Mode_Tx,允许使用逻辑或运算选择两个,它设定USART_CR1寄存器的RE位和TX位。
  6. USART_HardwareFlowControl:硬件流控制选择,只有在硬件控制模式下才有效。
串口通信实例

学习完串口的相关知识,肯定需要一个例子来实现。下面我们来制作一个简单的串口发送项目。

其中配置串口函数,一般分为中断和非中断两种配置方法,我会分别进行介绍。

非中断实现

非中断配置串口函数,只需要编写Usart1_Configuration函数即可。

void Usart1_Configuration(u32 BAUD)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    //第一步:初始化时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    //第二步:初始化GPIO
    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
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
    //第三步:初始化串口参数
    USART_InitStructure.USART_BaudRate = BAUD;//串口波特率
    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_Cmd(USART1, ENABLE);                    //使能串口1
    USART_ClearFlag(USART1, USART_FLAG_TC);       //清空发送完成标志
}
中断实现

中断配置串口函数,除了编写Usart1_Configuration函数还需要配置中断。

  1. 串口1中断配置
static void Usart1_NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
    NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
  1. 串口1配置函数
void Usart1_Configuration(u32 BAUD)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    //第一步:初始化时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    //第二步:初始化GPIO
    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

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

    //第三步:初始化串口参数
    USART_InitStructure.USART_BaudRate = BAUD;//串口波特率
    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_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断

    //第五步:配置中断优先级
    Usart1_NVIC_Configuration();

    //第六步:使能串口
    USART_Cmd(USART1, ENABLE);                    //使能串口1
    USART_ClearFlag(USART1, USART_FLAG_TC);       //清空发送完成标志
}
发送数据
  1. 串口1发送一个字节
void Usart1_SendByte(u8 val)
{
    USART_SendData(USART1, val);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);	//等待发送完成
}
  1. 串口1发送一个数据包
void Usart1_SendBuf(u8 *buf,u8 len)
{
    while(len--)	Usart1_SendByte(*buf++);
}
  1. 串口1发送一个字符串
void Usart1_SendString(char *str)
{
    while(*str)	Usart1_SendByte(*str++);
}
使用

我们使用的时候,只需要先初始化串口1配置函数Usart1_Configuration(选择自己想要设定的波特率); 之后调用发送函数Usart1_SendString(“发送的内容”); 即可。

int main(void)
{	
	Usart1_Configuration(115200);
	while(1){
	……
	Usart1_SendString("  usart1 is ok!\r\n");
	}
}
后续

如果想了解更多物联网、智能家居项目知识,可以关注我的项目实战专栏。 或者关注公众号观看更多。 在这里插入图片描述

编写不易,感谢支持。

关注
打赏
1663745539
查看更多评论
立即登录/注册

微信扫码登录

0.1503s