【STM32】串口收发驱动Drv_Uart|学习笔记
一、什么事串口?
大家常说串口,其实串口有很多种UART,SPI,IIC都是串口,一般大家口中的串口就是UART(Universal Asynchronous Receiver/Transmitter),STM32上集成了UART的控制器,所以我们通过简单的配置就可以实现UART通信的功能。当然光有控制器可以在单板间通信,但大部分的应用场景都是需要远距离的抗干扰传输,这时就需要做电平转换,,目前工业上常用的串口屏,串口透传zigbee,诸如此类的设备都会用到标准的串行接口,所以单板上一般会加一个收发器,来实现电平转换,常用的串行接口就是大家常说的232,485,422等。
对于STM32来说不同的接口控制方法基本类似(就两线制来说),485会多一条读写的控制引脚,因为它是半双工,不能同时读写。
二、怎样使用它?
1.串口外设使能,GPIO使能
RCC_APB2PeriphClockCmd();
2.串口复位
USART_DeInit();
3.GPIO模式设置
GPIO_Init();
GPIO_PinAFConfig();
4.串口参数初始化
USART_Init();
5.开启中断并初始化NVIC
NVIC_Init();
USART_ITConfig();
6.使能串口
UART_Cmd();
7.编写中断处理函数
USARTx_IRQHandler();
8.串口数据收发
void USART_SendData();
u8 USART_ReceiveData();
贴一个配置代码
这是串口控制器结构体
- typedef struct Com_Manager
- {
- u8 Status;
- u8 Send_Buf[256];
- u16 TxByte_Counter;
- u16 Stop_Byte;
- u8 Recv_Buf[256];
- u16 RxByte_Counter;
- u16 OverTime_cnt;
- }Com_Manager;
函数实现
- void InitUart4(u32 bdr)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- USART_InitTypeDef USART_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);//IO时钟UART时钟不用说一定都要开启先
- GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_UART4);
- GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_UART4);//F2系列必须有这一句去开启IO的复用功能
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOC,&GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOC,&GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOE,&GPIO_InitStructure);
- UART4_DIR_RX();//这里哦那个
- USART_DeInit(UART4);
- USART_InitStructure.USART_BaudRate = bdr;
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Parity = USART_Parity_No;
- USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
- USART_Init(UART4,&USART_InitStructure);//UART配置
- NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_Init(&NVIC_InitStructure);//NVIC配置
- USART_ITConfig(UART4,USART_IT_RXNE,ENABLE);//可以查参考手册中关于串口中断的部分,RXNE指的是接收完成中断,每当接收到一个字节就进一次中断。
- USART_Cmd(UART4,ENABLE);//启动UART
- }
- void UART4_IRQHandler()//UART USART要注意区分
- {
- if((USART_GetITStatus(UART4,USART_IT_RXNE))&&((Com[4].Status&0x06) == 0x00))
- {
- //建立接收
- Com[4].Status |= COM_RECEIVING;
- Com[4].Recv_Buf[Com[4].RxByte_Counter] = USART_ReceiveData(UART4);
- Com[4].RxByte_Counter++;
- Com[4].OverTime_cnt = 0;
- if(Com[4].RxByte_Counter > 255)
- {
- Com[4].RxByte_Counter = 0;
- Com[4].Status = COM_RECVFULL;//没想好怎么处理
- }
- }
- }
- u8 Drv_Uart_Async_Send(Com_Manager* port,u8* send_buf,u16 buf_size)
- {
- if((buf_size < 256)&&((port->Status&0x03) == 0x00))
- {
- //建立发送
- port->Status |= COM_SENDING;
- port->Stop_Byte = buf_size;
- port->TxByte_Counter = 0;
- memcpy(port->Send_Buf,send_buf,buf_size);
- return 1;
- }
- else
- {
- //错误类型分类返回
- return 0;
- }
- }
- u16 Drv_Uart_Async_Recv(Com_Manager* port,u8 *recv_buf)
- {
- u16 counter_saver;
- if((port->Status&COM_RECVCOMPLETE) == COM_RECVCOMPLETE)
- {
- if(port->RxByte_Counter > 0)
- {
- counter_saver = port->RxByte_Counter;
- memcpy(recv_buf,port->Recv_Buf,port->RxByte_Counter);
- port->RxByte_Counter = 0;
- port->OverTime_cnt = 0;
- port->Status &= ~COM_RECVCOMPLETE;
- return counter_saver;
- }
- else
- {
- return 0;
- }
- }
- else
- {
- return 0;
- }
- }
发送这里用到了定时器,我用了50us来刷新是否有新建的发送任务及正在发送的任务,累计500us没有收到数据认为接收完成。
- void Drv_Uart_50us_do()
- {
- //Com2循环发送处理************************************************************
- if((Com[2].Status&COM_SENDING) == COM_SENDING)
- {
- if(USART_GetFlagStatus(USART2,USART_FLAG_TC) != RESET)
- {
- UART2_DIR_TX();
- USART_SendData(USART2,Com[2].Send_Buf[Com[2].TxByte_Counter++]);
- if(Com[2].TxByte_Counter > Com[2].Stop_Byte)
- {
- UART2_DIR_RX();//非常重要 坑了我一天 发送完必须复位RE 否则进不了接收中断
- Com[2].Status &= ~COM_SENDING;
- Com[2].TxByte_Counter = 0;
- Com[2].Stop_Byte = 0;
- }
- }
- }
- //Com2接收超时处理
- else if((Com[2].Status&COM_RECEIVING) == COM_RECEIVING)
- {
- Com[2].OverTime_cnt++;
- if(Com[2].OverTime_cnt >= 10)
- {
- Com[2].Status |= COM_RECVCOMPLETE;
- Com[2].Status &= ~COM_RECEIVING;//5ms仍未接收到数据认为接收完成
- }
- }
- }
我这里用了一种状态处理机制,来保证485的半双工正常工作,简单来说就是收的时候不能发送发的时候不能接收,收发互斥。
但是这样做存在一个问题就是如果接受的数据没有及时处理,那么会造成一个死锁,接下来优化考虑用堆栈来接收数据,把接收到的数据压入栈,需要读的时候弹栈。
【STM32】串口收发驱动Drv_Uart|学习笔记的更多相关文章
- 驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址
驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址 最近重新看了乾龙_Heron的<ARM 上电启动及 Uboot 代码分析>(下简称<代码分析>) ...
- 基于STM32的USB枚举过程学习笔记
源:基于STM32的USB枚举过程学习笔记 基于STM32的USB枚举过程学习笔记(一) 基于STM32的USB枚举过程学习笔记(二) 基于STM32的USB枚举过程学习笔记(三) 基于STM32的U ...
- stm32串口收发导致的死机
stm32串口收发导致的死机 很久以前有偶尔遇到过串口死机的情况,那是当时的我写出来的代码自己都觉得有问题,也就没注意.用了stm32做项目以后也就没遇到过了,今天做了个高压测试,每5ms定时发送一次 ...
- 驱动开发学习笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇
驱动开发读书笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇下面这段摘自 linux源码里面的文档 : Documentatio ...
- 驱动开发学习笔记. 0.02 基于EASYARM-IMX283 烧写uboot和linux系统
驱动开发读书笔记. 0.02 基于EASYARM-IMX283 怎么烧写自己裁剪的linux内核?(非所有arm9通用) 手上有一块tq2440,但是不知道什么原因,没有办法烧boot进norflas ...
- 驱动开发学习笔记. 0.06 嵌入式linux视频开发之预备知识
驱动开发读书笔记. 0.06 嵌入式linux视频开发之预备知识 由于毕业设计选择了嵌入式linux视频开发相关的项目,于是找了相关的资料,下面是一下预备知识 UVC : UVC,全称为:USB v ...
- 驱动开发学习笔记. 0.05 linux 2.6 platform device register 平台设备注册 2/2 共2篇
驱动开发读书笔记. 0.05 linux 2.6 platform device register 平台设备注册 2/2 共2篇 下面这段摘自 linux源码里面的文档 : 内核版本2.6.22Doc ...
- 驱动开发学习笔记. 0.01 配置arm-linux-gcc 交叉编译器
驱动开发读书笔记. 0.01 配置arm-linux-gcc 交叉编译器 什么是gcc: 就像windows上的VS 工具,用来编译代码,具体请自己搜索相关资料 怎么用PC机的gcc 和 arm-li ...
- 基于STM32的USB枚举过程学习笔记(转)
之前使用ST官方的库以及网络的资料,完成了使用USB HID类进行STM32和PC机的通讯.由于其他原因并没有深入的分析,虽然实现了功能,但是关于USB设备的枚举,以及具体的通讯方式都没有清晰的概念, ...
- stm32串口通信实验,一点笔记
第一次深入学习stm32,花了好长时间才看懂代码(主要是C语言学习不够深入),又花了段时间自己敲了一遍,然后比对教程,了解了利用中断来串口通信的设置方法. 板子是探索版f407,本实验工程把正点原子库 ...
随机推荐
- 关于hbulider开发工具微信小程序请求跨域
问题描述: 1.thinkphp设置了跨域请求设置 2.接口在浏览器模式正常请求 3.微信小程序请求显示跨域 解决方案:
- RDD编程练习
一.filter,map,flatmap练习: 1.读文本文件生成RDD lines 2.将一行一行的文本分割成单词 words 3.全部转换为小写 4.去掉长度小于3的单词 5.去掉停用词 6.练习 ...
- [整合] 解决 Dell T640 安装显卡后风扇转速不降低
最近实验室的dell T640服务器安装了新的GPU.但是安装后发现,风扇太吵了,于是开始着手解决风扇转速过高的问题. 试过ipmi,但是不好用. 最后发现使用racadm可以让服务器重新安静下来. ...
- seqsever 查询多个表的条数,并以列的形式展现
select sum(a) a,sum(b) b,sum(c) c,SUM(d) d,sum(a1) a1,sum(b1) b1,sum(c1) c1,SUM(d1) d1 from( select ...
- MNIST数据集output with shape [1, 28, 28] doesn't match the broadcast shape [3, 28, 28]
transform = transforms.Compose([ transforms.ToTensor(), transforms.Lambda(lambda x: x.repeat(3,1,1)) ...
- sheet.getLastRowNum()获取行数不准的问题
// 获得总共有多少行int rowNum = 0;//存在样式的空行.会被统计进来.所以主要的问题是要判断是否是空行.for (int num = 1; num <= sheet.getLas ...
- List循环问题
list循环时的问题,报错,称找不到该字段属性,原因如下: 1.字段名与toString里不匹配: 2.首字母大写了: 原回答:https://blog.csdn.net/qq_42671193/ar ...
- python经典例题
[程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? num_list=[] cou=0 for i in range(1,5): for j in rang ...
- [SSH-1]publickey,gssapi-keyex,gssapi-with-mic
实际上,是有两个不同的原因的,它们都会造成这个报错. 原因1)client端私钥文件权限太大 解决方法:chmod 400 ~/.ssh/id_rsa #如果是RSA算法的话,私钥生成时默认叫id_ ...
- lua如何转化为exe
在这里下载 https://wwn.lanzout.com/iIS9d07rpesh 然后用cmd到 下载的盘:\luapack\luapack\bin\Debug 然后glue.exe srl ...