一、串口中断+超时解析
1. CubeMX配置
1.1 属性配置
主要配置波特率,其余默认
中断配置
Preemption Priority:抢占优先级
Sub Priority: 子优先级
串口的DMA设置
只开接收DMA即可
DMA的模式:
- Normol
- Circual
2. 驱动程序编写
2.1 串口重定向
在uasrt.c中进行修改
1 | int fputc(int ch, FILE * stc) |
2.2 app_uart.c 变量定义
1 | uint16_t uart_rx_index = 0; |
2.3 中断初始化
放入Core->Src->usart.c中
在初始化中使能串口中断,往buffer中每次填充一个字节,触发中断回调
1 | HAL_UART_Receive_IT(&huart1,uart_rx_buffer,1); |
- Hal库——中断回调函数
2.4 回调函数声明
弱定义
自定义回调函数
可以自行声明与弱定义回调函数同名的函数,会优先执行自定义的函数
Hal库中各种弱定义都是用__weak修饰的
过程:串口接收->触发回调->进入回调函数
PS: void HAL_UART_RxCpliCallback(UART_HandleTypeDef *huart) 不要用成 void HAL_UART_TxCpliCallback(UART_HandleTypeDef *huart)
1 | void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) |
2.5 串口解析
超时解析
1 | void uart_proc(void) |
# 无DMA和环形缓冲区的问题
当串口接收速率过快时,如视觉上位机频繁向单片机发送识别到的坐标数据,可能会导致单片机程序阻塞
1. 串口阻塞的解决方案
DMA:数据转运
RingBuffer:环形缓存区
2. # 环形缓冲区的概念:
- 头指针
- 尾指针
# 现象:
1. 串口无解析发送上位机
CubeMX未定义串口引脚,未注意STM32外设引脚可复用问题
2. 回调函数名称错误
二、DMA+空闲中断
# DMA的作用
无DMA:数据->Uart寄存器->CPU访问Uart寄存器->执行其他程序部分
-------如果串口通信速率过快------>CPU频繁访问Uart寄存器-------->程序阻塞
有DMA:数据->Uart->DMA访问Uart数据->存放到单片机内存地址
CPU与DMA并行工作
在上述配置的基础上对程序文件进行进一步修改。
1. 变量声明
声明 uart_rx_dma_buffer变量,用于数据转运
2. 中断初始化
启用DMA相关中断
关闭DMA半中断
PS: 不再适用串口回调,改用DMA的方法
3. 串口中断函数
每次触发串口中断,触发DMA中断
取消使用串口中断回调函数
改用空闲中断回调函数
PS: 不再需要串口超时解析
# 现象:
# 补充——中断函数与回调函数的区别
在嵌入式编程中,HAL(硬件抽象层)库的中断函数和回调函数是常见的机制,尤其是在处理外设操作时。这两者的作用有时容易混淆,但它们的概念和使用场景有所不同。下面详细解释它们的区别:
1. 中断函数(Interrupt Service Routine, ISR)
中断函数是一段处理硬件中断的代码。当外设或处理器触发中断时,处理器会暂停当前的代码执行,转而执行与该中断对应的ISR。一旦中断被处理完毕,程序会恢复到原来的执行状态。
- 执行方式:硬件触发,直接由处理器执行,通常是高优先级。
- 响应时间:要求短小精悍,不能执行耗时的任务,因为会阻塞其他中断。
- 位置:ISR通常定义在HAL库或用户代码中,是一个固定的函数(如
TIM_IRQHandler
等)。- 调用方式:自动触发,由硬件中断控制器(NVIC)决定何时调用中断处理函数。
2. 回调函数(Callback Function)
回调函数是一个函数指针,通过预先注册到某个模块或API中,等到某个事件发生时,由该模块或API负责调用。HAL库中的回调函数通常是在中断处理完毕后,由ISR或HAL库内部调用,用来进一步处理用户逻辑。
- 执行方式:由程序代码(比如ISR或定时器事件)调用,响应某个事件。
- 响应时间:回调函数不要求像中断处理函数那样必须快速完成,往往用于处理稍复杂的业务逻辑。
- 位置:回调函数通常由用户实现,并由HAL库的中断处理函数或其他机制调用(如
HAL_TIM_PeriodElapsedCallback
)。- 调用方式:回调函数不是直接由硬件触发,而是由软件触发,即当中断函数处理完硬件中断后,再调用用户注册的回调函数。
简单总结区别:
- 触发机制:中断函数是由硬件事件(如定时器溢出、外部信号等)直接触发,而回调函数是由软件(如ISR)触发。
- 职责范围:中断函数负责处理硬件中断,通常需要快速执行;回调函数则处理用户定义的业务逻辑,通常可以有更多的处理空间和时间。
- 优先级:中断函数的优先级较高,回调函数的执行时间不受硬件中断控制,通常在中断函数结束之后才执行。
典型应用场景
以定时器为例:
- 当定时器溢出时,触发一个中断,执行定时器的中断函数
TIM_IRQHandler
。- 在中断函数内部,可能会调用HAL库的定时器回调函数
HAL_TIM_PeriodElapsedCallback
,用于用户自定义的定时器周期性任务处理。这就是中断函数和回调函数的核心区别。
三、环形缓冲区
# 环形缓冲区的简介
待补充
1. 移植环形缓冲区驱动文件
1 | ringbuffer_t usart_rb; //定义ringbuffer_t类型结构体变量 |
- 判断ringbuffer是否满
- 写入数据
- 清空结构体
2. 修改串口解析
1 | void uart_proc() |
STM32串口通信方法总结:
-
超时解析
-
DMA空闲中断
-
环形缓存区
四、ADC和DMA
STM32的ADC(模数转换器)通道IN11指的是STM32微控制器上一个特定的ADC输入通道。每个STM32芯片的ADC都有多个模拟输入引脚,这些引脚标记为
INx
(例如IN0、IN1、IN2等),对应不同的GPIO引脚。具体到IN11,它是ADC的第11个输入通道,通常与一个特定的GPIO引脚连接。该引脚用于将模拟信号输入到ADC进行模数转换。
CT117E原理图:
1. CubeMX配置
1.1 ADC通道分配:
- ADC1: IN11
- ADC2: IN15
1.2 配置DMA
1.2.1 配置DMA通道
1.2.2 配置为循环模式
1.2.3 配置DMA速度
设置为中、高均可
1.3 配置ADC属性
- 四分频
- DMA使能
- 循环使能
1.4 配置ADC中断
优先级为2即可
2. 驱动程序编写
2.1 创建adc_app.c
变量声明
1 |
|
在主程序初始化启用DMA 转运 ADC 数据
2.2 定义ADC进程
- 读取电压dma储存数据
- 转换为模拟电压值
同样的,记得在任务调度器中添加proc
2.3 lcd显示
# 动态窗口
- 使用环形缓存区
- 定义结构体