单片机入门学习十 STM32单片机学习七 串口通讯

单片机入门学习三 51单片机学习二 中已经说了串口通讯的基本原理,本篇主要记录stm32中的串口通讯。

1、串口通讯基础简单回顾

1)串口通讯通讯方式
  • 同步通信:带时钟同步信号传输。SPI,I²C通信接口
  • 异步通信:不带时钟同步信号。UART(通用异步收发器),单总线
2)串行通讯接口
通讯标准引脚说明通信方式通信方向
UART
(通用一步收发器)
TXD:发送端
RXD接收端
GND公共地
异步通讯全双工
单总线
(1-wire)
DQ:发送/接收端异步通讯半双工
SPISCK:同步时钟
MISO:主机输入,从机输出
MOSI:主机输出,从机输入
同步通讯全双工
I²CSCL:同步时钟
SDA:数据输入/输出端
同步通讯半双工

stm32的串口通信接口(stm32f10x系列芯片,包含3个USART、2个UART)

  • UART:通用异步收发器
  • USART:通用同步异步收发器
3)UART引脚连接方法

① 单片机连接单片机
UART
② 单片机连接PC
UART
PC机使用的是RS232电平标准,而单片机采用的是 TTL电平,所以需要 连接一个RS232转换器 将TTL电平转换成 PC可以识别的RS232电平

4)UART异步通信特点
  • 全双工异步通信。
  • 分数波特率发生器系统,提供精确的波特率。发送和接受共用的可编程波特率,最高可达4.5Mbits/s
  • 可编程的数据字长度(8位或者9位);
  • 可配置的停止位(支持1或者2位停止位);
  • 可配置的使用DMA多缓冲器通信。
  • 单独的发送器和接收器使能位。
  • 检测标志:① 接受缓冲器 ②发送缓冲器空 ③传输结束标志
  • 多个带标志的中断源。触发中断。

5)串口通信过程

① 数据接收过程
外部设备将数据发送到 串行输入移位寄存器,串行输入移位寄存器在将数据传送到输入数据缓冲器,MCU在从输入数据缓冲器中读出数据
接收
② 数据发送过程
MCU将要发送的数据写入输出数据缓冲器,输出数据缓冲器在将数据写入串行输出移位寄存器,串行移位寄存器在将数据输出到外部设备
发送

6)USART概述

通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。
它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。
使用多缓冲器配置的DMA方式,可以实现高速数据通信。

任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。
RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。
● 总线在发送或接收前应处于空闲状态
● 一个起始位
● 一个数据字(8或9位),最低有效位在前
● 0.5,1.5,2个的停止位,由此表明数据帧的结束
● 使用分数波特率发生器 —— 12位整数和4位小数的表示方法。
● 一个状态寄存器(USART_SR)
● 数据寄存器(USART_DR)
● 一个波特率寄存器(USART_BRR),12位的整数和4位小数
● 一个智能卡模式下的保护时间寄存器(USART_GTPR)

下图是USART通讯的示意图
USART框图

下图是STM32串口异步通信需要定义的参数
STM32异步通信参数:
①起始位
②数据位(8位或者9位)
③奇偶校验位(第9位)
④停止位(1,15,2位)
⑤波特率设置
参数

上图中红色的线表示 芯片读取 PC端发送的信息,绿色的线表示 发送数据到PC,枚红色的线表示 时钟线。

7)USART常用数据寄存器

USART_SR状态寄存器
USART_SR
USART_DR数据寄存器
DR
USART_BRR波特率寄存器
BRR
波特率计算方法:

波特率计算

8)串口操作相关库函数

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);//串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能
void USART_Cmd();//使能串口
void USART_ITConfig();//使能相关中断

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);//发送数据到串口,DR
uint16_t uint16_t USART_ReceiveData(USART_TypeDef* USARTx);//接受数据,从DR读取接受到的数据

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);//获取状态标志位 读取的是USART_SR寄存器
void USART_ClearFlag();//清除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearITPendingBit();//清除中断状态标志位

9)串口配置一般步骤

①串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
②串口复位:USART_DeInit(); 这一步不是必须的
③GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF_PP(RX),GPIO_Mode_AF_Float(TX)
④串口参数初始化:USART_Init();
⑤开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
NVIC_Init();
USART_ITConfig();
⑥使能串口:USART_Cmd();
⑦编写中断处理函数:USARTx_IRQHandler();
⑧串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
⑨串口传输状态获取:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

2、串口编程

下面是所学的串口实现课程的源码
usart.c

//串口1中断服务程序
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,    接收完成标志
//bit14,    接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记    

void uart_init(u32 bound)
{
    //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   GPIOA.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);//初始化GPIOA.9

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

    //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;//串口波特率
    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_Cmd(USART1, ENABLE);                    //使能串口1 

}

void USART1_IRQHandler(void)                    //串口1中断服务程序
{
    u8 Res;
    #if SYSTEM_SUPPORT_OS       //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
    OSIntEnter();    
    #endif
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
        Res =USART_ReceiveData(USART1); //读取接收到的数据

        if((USART_RX_STA&0x8000)==0)//接收未完成
        {
            if(USART_RX_STA&0x4000)//接收到了0x0d
            {
                if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
                else USART_RX_STA|=0x8000;  //接收完成了 
            }
            else //还没收到0X0D
            {   
                if(Res==0x0d)USART_RX_STA|=0x4000;
                else
                {
                    USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
                    USART_RX_STA++;
                    if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收      
                }        
            }
        }            
    } 
 }

main.c

 int main(void)
 {      
    u16 t;  
    u16 len;    
    u16 times=0;
    delay_init();            //延时函数初始化    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200);   //串口初始化为115200
    while(1)
    {
        if(USART_RX_STA&0x8000)
        {                      
            len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
            printf("\r\n您发送的消息为:\r\n\r\n");
            for(t=0;t<len;t++)
            {
                USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
            }
            printf("\r\n\r\n");//插入换行
            USART_RX_STA=0;
        }
        else
        {
            times++;
            if(times%5000==0)
            {
                printf("\r\n战舰STM32开发板 串口实验\r\n");
                printf("正点原子@ALIENTEK\r\n\r\n");
            }
            if(times%200==0)printf("请输入数据,以回车键结束\n");  
            if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
            delay_ms(10);   
        }
    }    
 }
  • 18
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风水月

从心底相信自己是成功的第一步

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值