• 正文
  • 相关推荐
申请入驻 产业图谱

【FOC相关外设】UART的应用

07/15 08:03
283
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、串口基础知识

串口是指外设和处理器之间通过数据信号线、地线和控制线等,按位进行传输数据的一种通讯方式。尽管传输速度比并行传输低。但串口可以在使用一根线发送数据的同时用另一根线接收数据。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验位,这些参数在两个通信端口之间必须一致。

二、串口通信参数介绍

波特率: 衡量通信速度的参数,它表示每秒钟传送的bit的个数。

数据位: 衡量通信中实际数据位的参数,表示一个信息包里包含的数据位的个数。

停止位: 用于表示单个信息包的最后位,典型值为1、1.5和2位。由于数据是在传输线上传输的,每个设备都有自己的时钟,很有可能在通信过程中出现不同步,停止位不仅仅表示传输的结束,还能提供校正时钟同步的机会。停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率也越慢。

奇偶检验位: 表示一种简单的检查错误的方式。

硬件数据流控:通过使用专用的控制线(通常称为RTS和CTS来协调发送方和接收方之间的数据传输过程,以防止数据丢失或溢出。

三、串口工作模式

串口可以工作在异步全双工 、同步半双工 和单线半双工模式下。

异步全双工:

异步:指的是通信双方不需要共享一个共同的时钟信号。数据传输的起始和结束通过特定的帧格式、起始位、停止位或者特定的同步字符来标识,允许发送和接收端各自独立工作,不必严格同步它们的时钟。这使得异步通信更加灵活,但可能引入一些开销,如额外的同步信息。

全双工:表示数据可以同时在两个方向上传输。也就是说,通信双方都能同时发送和接收数据,如同有两个独立的通道,互不影响,提高了通信效率,适合于需要高速、双向实时通信的场景,如以太网通信。

同步半双工:

同步:在同步通信中,发送和接收设备之间需要一个共同的时钟信号,用以同步数据的传输节奏。这通常通过一个时钟引脚或在数据流中嵌入同步位来实现。同步通信可以提供更高的数据传输速率,因为它减少了用于数据包同步的开销。

半双工:半双工模式允许数据在两个方向上传输,但不能同时进行。通信双方需要轮流进行发送和接收。例如,经典的RS-485总线在半双工模式下,一次只能进行发送或接收操作,需要通过控制线切换方向。这种方式适用于对实时性要求不高、双向通信但不需要同时收发的场合。

单线半双工:

单线半双工:这种模式通常特指使用一根信号线既用于发送也用于接收数据,但不能同时进行,属于半双工通信的一种特殊形式。

四、串口工作模式

串口在进行通信的时候会按照数据包的形式进行发送,帧格式如下图。

串口通信是一位一位地传输,每传输一个字节总是以起始位开始,以停止位结束,字符之间没有固定的时间间隔要求。每一个字符的前面都有一位起始位(低电平),后面由8位数据位组成,如果开启了校验位,则最后一位数据位是校验位,最后是停止位。停止位后面是不定长的空闲位,停止位和空闲位都规定为高电平

五、串口接线图

我们这里使用的是PB11(RX引脚)和PB12(TX引脚),对应CW32L012的UART1,这里需要把板子上的TX连接到下载器上的RX,板子上的RX连接到下载器的TX,以下是接线图

六、配置流程

一般我们使用串口,都需要有以下几个步骤。

开启时钟(包括串口时钟和GPIO时钟)

配置GPIO复用模式

配置GPIO的模式

配置GPIO的输出

配置串口(配置一些参数)

使能串口(串口使能和发送使能)

七、开启时钟

使用UART1的话就是PB11和PB12引脚。那第一步就是先开启GPIOB的时钟,在库函数点灯那一章节给大家介绍了使能时钟的函数__SYSCTRL_GPIOC_CLK_ENABLE,使能GPIOB的时钟就把GPIOC换成GPIOB就可以了,__SYSCTRL_GPIOB_CLK_ENABLE();

第二步就是开启串口的时钟,使用__SYSCTRL_UART1_CLK_ENABLE。

//配置RCC __SYSCTRL_GPIOB_CLK_ENABLE();         // 使能GPIO时钟__SYSCTRL_UART1_CLK_ENABLE();        // 使能串口时钟

八、配置GPIO

配置GPIO的模式还是使用GPIO_Init这个函数,默认是GPIO口,串口是这个IO口上的复用功能,所以还需要调用对应IO的复用功能,使用每个端口上的宏定义PB11_AFx_UART1RXD,PB12_AFx_UART1TXD开启复用功能,转化为代码如下。

    GPIO_InitTypeDef GPIO_InitStruct;    GPIO_InitStruct.IT = GPIO_IT_NONE;    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;    GPIO_InitStruct.Pins = GPIO_PIN_11 | GPIO_PIN_12;    GPIO_Init(CW_GPIOB, &GPIO_InitStruct);    PB11_AFx_UART1RXD();    PB12_AFx_UART1TXD();

九、配置串口

我们依然使用结构体的方式进行配置串口数据,里面有些参数是必须要配置的:

波特率:通讯的速率

字节长度:8位

停止位:1位停止位

校验位:不需要校验位

收发模式:收发

流控选择:不流控

相关的代码:

    UART_InitTypeDef UART_InitStruct;    UART_InitStruct.UART_BaudRate = 115200;    UART_InitStruct.UART_Over = UART_Over_16;    UART_InitStruct.UART_Source = UART_Source_PCLK;    UART_InitStruct.UART_UclkFreq = 96000000;    UART_InitStruct.UART_StartBit = UART_StartBit_LL;    UART_InitStruct.UART_StopBits = UART_StopBits_1;    UART_InitStruct.UART_Parity = UART_Parity_No;    UART_InitStruct.UART_Mode = UART_Mode_Tx | UART_Mode_Rx;    UART_InitStruct.UART_HardwareFlowControl = UART_HardwareFlowControl_None;    UART_Init(CW_UART1, &UART_InitStruct);

十、配置中断

我们并不知道串口什么时候会发回来消息,轮询等待是不现实的,所以我们需要中断来帮我们监控,如果有数据发来,则进入中断进行处理。 转化为代码为:

    NVIC_SetPriority(UART1_IRQn, 3);    NVIC_EnableIRQ(UART1_IRQn);    UART_ITConfig(CW_UART1, UART_IT_RC | UART_IT_RXIDLE, ENABLE);

十一、编写串口中断服务函数

void UART1_IRQHandler(void){    if (UART_GetITStatus(CW_UART1, UART_IT_RC) == SET)    {        UART_ClearITPendingBit(CW_UART1, UART_IT_RC);        receive_buffer[receive_buffer_index++] = UART_ReceiveData(CW_UART1);    }    else if (UART_GetITStatus(CW_UART1, UART_IT_RXIDLE) == SET)    {        UART_ClearITPendingBit(CW_UART1, UART_IT_RXIDLE);        isover = 1;    }}

中断入口:函数开始直接进入中断处理逻辑。

中断状态检查:通过USART_GetITStatus(USART1, UART_IT_RC)检查是否是因为接收中断(UART_IT_RC表示接收中断)触发了中断。如果不是接收中断,则不执行后续操作。

数据接收:如果接收中断发生,通过receive_buffer数组读取接收到的一个字节数据,并将其存储在这个全局数组中

在这个部分就可以编写其他的处理。

数据接收完成中断:通过UART_GetITStatus(CW_UART1, UART_IT_RXIDLE)检查数据是否接收完成,接收完成将isover标志位置1,通知主函数那边,接收数据已完成,可以执行操作了。最后,通过USART_ClearITPendingBit(USART1, UART_IT_RXIDLE),UART_ClearITPendingBit(CW_UART1, UART_IT_RC)清除接收中断相关的标志位,这是非常重要的一步,以避免下次同类型中断发生前,中断标志一直保持激活状态,造成重复中断处理。

到此,串口使能就可以使用了。

十二、串口发送数据

配置好串口之后,下一步的操作就是要发送数据。

void UART1_SendByte(uint8_t byte){    while (UART_GetFlagStatus(CW_UART1, UART_FLAG_TXE) == RESET);    {    }    UART_SendData(CW_UART1, byte);}void UART1_SendBytes(uint8_t* bytes, uint16_t len){    while (len--)    {        UART1_SendByte(*bytes++);    }}

十三、实验现象

烧写我们的代码之后,打开串口调试助手,我们在串口助手中发送一条数据,012芯片接收到以后,又会在主程序中给我们发送回来,所以在串口助手中我们可以看到两条相同的数据:

实验例程下载文件:

通过网盘分享的文件:UART.zip

链接: https://pan.baidu.com/s/1XwMr5zOc13lGZV3Fmso89w?pwd=L012 提取码: L012

 


扫码加入QQ群 3群| 610403240

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

以开放、共享、互助为理念,致力于构建武汉芯源半导体CW32系列MCU生态社区。无论是嵌入式MCU小自还是想要攻破技术难题的工程师,亦或是需求解决方案的产品经理都可在CW32生态社区汲取营养、共同成长。