【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,本实验工程把正点原子库 ...
随机推荐
- FTP调优
最近在解决客户的问题时接触到了一些FTP的问题,自己在使用过程中发现了很多问题,所以这里总结了一些调优的办法: 服务:vsftp 非常安全文件传输 配置文件:/etc/vsftpd/vsftpd.co ...
- 运行Java时报错:Error: opening registry key 'Software\JavaSoft\Java Runtime Environment'
卸载旧的JAVA JDK,安装新版的JDK时,运行cmd的java -version命令遇到这样的报错: Error: opening registry key 'Software\JavaSoft\ ...
- leetcode 31. 下一个排列 【时间击败 100%】 【内存击败 92.17%】
对于该题,我本来兴致勃勃地想到了两个优化,但从提交结果来看根本看不出来有什么区别,但我发4我说的都是真的 -3- 1 public void nextPermutation(int[] nums) { ...
- Linux系统实时监控
命令 top Top命令用于实时显示process的动态.参数如下: d:设置显示的更新速度 q:无延迟的显示速度 c:切换显示模式,一共有两种显示模式,一是只显示执行档,另一种是显示 ...
- Oracle UNDO表空间的管理
Oracle UNDO表空间的管理 UNDO表空间的管理是Oracle DBA最重要的日常工作之一,UNDO表空间用来暂时存储DML操作的数据,其主要作用有: 1.事务回滚 2.实例恢复 3.读一致性 ...
- shell脚本:报错syntax error near unexpected token `$'\r''解决方法
之前的shell脚本是在服务器上编写的,后来又已复制的方式存在在了电脑上,以txt文件的形式存放的.于是复制到了编辑工具中,进行了相应项的修改.修改完毕后,拿到服务器上测试,结果执行sh XXX.sh ...
- Lua中创建新的文件夹
如下: os.execute('mkdir 文件夹名称')
- java-javaSE-异常机制
java中的异常结构 java 中的所有异常都来自于顶级父类 Throwable,Throwable 有两个子类 Exception 和 Error Error 是 Java 虚拟机无法解决的严重问题 ...
- 一个因为windows系统缺失文件而导致的pyspark的BUG
背景: 在windows 系统中开发pyspark程序. 一个简单的WC程序: from pyspark.sql import SparkSession spark = SparkSession.bu ...
- Apache SSI远程命令执行漏洞复现
漏洞原理:当目标服务器开启了SSI与CGI支持,就可以上传shtml文件,并利用语法执行任意命令,例如<!- - #exec cmd="ls"- ->,cmd后面跟要执 ...