stm32学习笔记004
[TOC]
任务(1):ADC 采样并通过串⼝发送⾄上位机
ADC简介
ADC原理(逐次比较型)
工作流程
初始化:
选择输入信号并设置参考电压。
采样:
ADC 读取输入模拟信号,并在采样保持电路中保持该值。
逐次比较:
ADC 开始进行逐次比较,将输入信号与内部的数字化值进行比较。这个过程通过一个逐次逼近寄存器实现。
设定一个初始的数字值(通常是中间值),然后将其转换为模拟信号(DAC 输出),并与输入信号进行比较。
比较结果:
如果 DAC 输出的模拟信号大于输入信号,则该位为 0;如果小于,则该位为 1。根据比较结果,SAR 更新其当前的数字值。
逐位比较过程从最高位到最低位进行,逐次确定每一位的值。
重复过程:
重复以上步骤,直到所有位都确定为止。一般来说,逐次比较型 ADC 的转换过程需要 N 次比较,其中 N 是 ADC 的分辨率(位数)。
输出结果:
一旦所有位都确定,转换结果就存储在输出寄存器中,可以通过数字接口读取。
ADC基本结构
ADC四种工作模式
- 单次转换,扫描:配置多个通道,每次扫描可以扫描多通道,但每个大过程都要用函数触发
- 单次转换,非扫描:配置单个同通道,每次扫描都要用一个函数触发一次
- 连续转换,扫描:配置多个通道,进行连续扫描,只需触发一次
- 连续转换,非扫描:配置一个通道,只扫描他,只需触发一次
转换时间
程序设计
(技术点介绍)首先是配置adc及其中断:
时钟配置
1 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); |
这两行代码开启了 ADC3 和 GPIOC 的时钟。只有在时钟开启后,ADC 才能工作
ADC 时钟分频
1 | RCC_ADCCLKConfig(RCC_PCLK2_Div6); |
此行设置 ADC 的时钟分频,2和4不能选,只能从6开始选
GPIO 配置
将 ADC 的输入引脚配置为模拟输入模式:
1 | GPIO_InitTypeDef GPIO_InitStructure; |
这里配置了 GPIOC 的 6 到 9 引脚为模拟输入,以便 ADC 可以读取这些引脚上的电压信号。
ADC 配置
使用 ADC_InitTypeDef
结构体配置 ADC 参数:
1 | ADC_InitTypeDef ADC_InitStructure; |
- 独立模式:表示此 ADC 不与其他 ADC 共享工作。
- 数据对齐:选择数据右对齐,可以更容易地处理和解析结果。
- 外部触发:这里设置为无外部触发,表示使用软件触发进行转换。
- 连续转换:设置为禁用,这样 ADC 只在每次软件触发时进行一次转换。
- 扫描模式:设置为禁用,表示只配置单个通道进行转换。
使能 ADC 和校准
1 | ADC_Cmd(ADC3, ENABLE); |
这些代码段使能 ADC,并进行校准以确保测量的准确性。校准过程包括重置校准状态和开始校准。
中断配置
1 | NVIC_InitTypeDef NVIC_InitStructure; |
- EOC 中断:使能 EOC 中断,这样 ADC 转换完成时会触发中断
数据读取和处理
启动 ADC 转换
在 AD_GetValue
函数中,选择通道并启动转换:
1 | ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5); |
这段代码根据输入参数配置要读取的 ADC 通道,并通过软件触发开始转换。ADC_SampleTime_55Cycles5
表示采样时间为 55.5 个 ADC 时钟周期,这是一个影响转换速度和精度的参数。
中断服务例程
中断服务例程负责处理 ADC 转换完成的事件:
1 | void ADC3_IRQHandler(void) |
- 检查 EOC 标志:如果 EOC 中断被触发,则读取 ADC 转换结果,并将其存储在
adc_value
中 - 清除中断标志:清除中断标志以便下次触发。
配置过程中,有几个点:
因为是单次转换,非连续模式,所以想让它持续工作,每次调用函数时都要手动
ADC_SoftwareStartConvCmd(ADC3, ENABLE)一次
因为程序没有用到dma,所以只能使用单通道,否则数据村不过来,因此就用四个通道周期性扫描的方式来完成
1 |
|
(技术点介绍,定时器中断)下面是timer.h
因为要获取时间间隔,所以配置tim定时器
思路如下:
- 定义一个全局变量 mytime
- 定义一个变量 last_time
- timer配置分频72-1,自动重装值1
- 配置中断,每次中断,mytime都加一,实现微秒级别的计数
- 当调用adc相关函数的时候,计算mytime与last_time的差值
1 |
|
主函数:
定义一个四个变量的数组,用于标志各个红外对管的状态,只有满足状态改变的判定条件时,再改变状态,防止串口那里一直乱跳
1 |
|
视频现象:
任务2 ——DMA转运数据
dma简介
技术点介绍
DMA 配置和使⽤
1 | //DMA初始化 |
DMA_InitTypeDef 结构体成员
DMA_PeripheralBaseAddr:
设置外设的基地址,DMA 传输时的源地址。
通常是外设寄存器的地址,比如 ADC 的数据寄存器 &ADC3->DR
DMA_PeripheralDataSize:
设置外设数据的宽度。
DMA_PeripheralDataSize_Byte:8位数据宽度
DMA_PeripheralDataSize_HalfWord:16位数据宽度(通常用于 ADC)
DMA_PeripheralDataSize_Word:32位数据宽度
DMA_PeripheralInc:
设置外设地址自增。
DMA_PeripheralInc_Disable:外设地址不自增(常用于 ADC)。
DMA_PeripheralInc_Enable:外设地址自增
DMA_MemoryBaseAddr:
设置存储器的基地址,DMA 将数据写入的目的地
通常是指向一个数组或内存区域的指针,例如 AD_Value
DMA_MemoryDataSize:
设置存储器数据的宽度。
DMA_Memorialized_Byte:8位数据宽度。
DMA_Memorialized_HalfWord:16位数据宽度。
DMA_Memorialized_Word:32位数据宽度。
DMA_MemoryInc:
设置存储器地址自增。
DMA_MemoryInc_Disable:存储器地址不自增(所有数据写入同一位置)。
DMA_MemoryInc_Enable:存储器地址自增(每次传输后,指向下一个存储单元)。
DMA_DIR:
设置数据传输的方向。
DMA_DIR_PeripheralSRC:从外设到存储器(如 ADC 到内存)。
DMA_DIR_MemorySRC:从存储器到外设(如内存到 DAC)。
DMA_BufferSize:
设置传输的数据大小(传输次数)。
指定传输的样本数量。例如,若你要从 ADC 获取 4 个样本,则设置为 4。
DMA_Mode:
设置 DMA 的工作模式。
DMA_Mode_Normal:正常模式,传输一次后停止。
DMA_Mode_Circular:循环模式,完成一次传输后自动重新开始,适合连续数据采集。
DMA_M2M:
设置存储器到存储器传输的使能。
DMA_M2M_Disable:禁用存储器到存储器的传输(通常用于外设到存储器传输)。
DMA_M2M_Enable:启用存储器到存储器的传输(适用于特定应用)。
DMA_Priority:
设置 DMA 传输的优先级。
DMA_Priority_Low:低优先级。
DMA_Priority_Medium:中优先级。
DMA_Priority_High:高优先级。
DMA_Priority_VeryHigh:最高优先级。
ADC 触发 DMA
DMA 配置:
在 ADC 初始化中,可以配置 DMA 使能。当 ADC 完成一次转换时,它会自动向 DMA 发送一个信号,指示数据已经准备好进行传输
1
ADC_DMACmd(ADC3, ENABLE);
数据传输:
一旦 DMA 接收到来自 ADC 的触发信号,它会从 ADC 的数据寄存器中读取转换结果,并将其存储到指定的内存地址(例如某个数组中)
定时器配置
10微秒为周期,以便记录微妙级别的DMA过程(也不是很精准,DMA转运太快了)
1 |
|
主函数源码
1 |
|
视频现象:
vofa
JustFloat 协议的结构
- 数据帧:
每个数据帧包含一个浮点数组,数组中的每个元素代表一个通道的数据。例如,有四个通道的数据要传输,数据帧中就要包含四个浮点数 - 小端格式:
JustFloat 协议使用小端格式存储浮点数,最低有效字节存储在最低的内存地址中 - 帧尾:
每个数据帧的末尾都有一个固定的帧尾标志,用于标识数据帧的结束: {0x00, 0x00, 0x80, 0x7f}
数据传输过程
数据准备:
需要传输的数据首先被转换成浮点数,并按照小端格式存储在数组中。
数据发送:
将浮点数组和帧尾标志一起发送到接收端。接收端通过识别帧尾标志来确定数据帧的结束,并解析浮点数组中的数据。数据解析:
接收端接收到数据帧后,解析浮点数组中的数据,并根据需要进行处理或显示。
应用场景
适合多通道数据采集,例如正在做的循迹小车有多个红外对管,每个红外对管代表一个通道的数据。
图形控件的使用
以最常用的示波器为例

在左侧选择控件示波器并把它拖进去
- 右键可以选择填充方式
- 下面三个圈可以调整波形范围,包含点数等
- auto可以让波形以最佳方式自动呈现
具体使用方法
配置一下这个能用这个协议的函数
1 |
|
- 这个函数中,前几行都是在进行数据处理,处理完成后得到tempdata,是一个uint8_t类型的数组
- 得到数组之后,用江科大的串口发送函数直接发到送即可
- 使用方法:输入(浮点数数组,数组长度)
配置ADC&&DMA
依然采用上面的配置,并将ADC数据接入拓展到12?个(咱只发了10个红外对管)
1 |
|
main函数调用
1 |
|
视频现象:
任务四:进行简单的循迹
外设原理
红外对管:红外对管循迹的原理主要是利用了不同颜色物体对红外线的反射和吸收能力不同。其基本工作过程如下:
红外发射:红外对管由一个红外发射管和一个红外接收管组成。红外发射管通电后会持续向外发射特定波长的红外线。
光线反射:当红外光线照射到物体表面时,根据物体的颜色和材质特性,会对红外线产生不同的反射情况。白色物体对光线的反射能力较强,能够将大部分照射到其表面的红外线反射出去;而黑色物体对光线的吸收能力较强,反射的红外线则较少。
接收与转换:红外接收管是一种对红外线敏感的光敏元件。当接收管接收到反射回来的红外线时,其内部的物理特性会发生变化,从而产生电流或电压的变化。如果接收到的红外光强度较大,接收管产生的电流或电压就会相应较大;反之,如果接收到的红外光很弱或几乎没有,接收管产生的电流或电压就会非常小。
信号输出与判断:通常会将红外接收管的输出信号连接到一个比较电路或信号处理电路。该电路会将接收管输出的信号与一个预设的阈值进行比较。如果接收管输出的信号大于阈值,说明接收到的红外光较强,此时判断为红外对管处于白色区域;如果接收管输出的信号小于阈值,说明接收到的红外光较弱,此时判断为红外对管处于黑色轨迹上。
基于以上原理,将红外对管安装在移动的物体(如智能小车)上,并合理设置多个红外对管的位置,就可以通过检测不同位置的红外对管信号,判断物体相对于黑线轨迹的位置,从而实现循迹功能。例如,当小车的左侧红外对管检测到黑色轨迹,而右侧红外对管检测到白色区域时,说明小车向左偏离了轨迹,控制系统就可以控制小车向右转,以保持在黑色轨迹上行驶。
循迹模块:根据红外对管反射回的信息,来判断小车行走的状态
5个红外对管安装在小车的对应位置
将ADC值转换为黑线1或者没有线0,红外对管从左往右分别为IPT0,IPT1,IPT2,IPT3,IPT4
我们根据反射回的信息将小车运动分为几种情况
PID:比例-积分-微分控制器,是一种常用的反馈控制算法,广泛应用于工业控制、自动化等领域。
基本原理
- 比例控制(P)
比例控制是根据当前的误差值与一个比例系数相乘来计算控制量。误差值是设定值与实际值之间的差值。
例如,如果设定温度为 50℃,当前实际温度为 45℃,误差为 5℃。假设比例系数为 2,那么比例控制的输出为 5×2 = 10。
比例控制的作用是对误差进行快速响应,但不能消除稳态误差,即当系统达到稳定状态时,可能仍然存在一定的误差。
- 积分控制(I)
积分控制是对误差进行累积求和,并将累积的误差与一个积分系数相乘来计算控制量。
随着时间的推移,积分项会不断增大,直到误差为零。积分控制的作用是消除稳态误差,但积分作用过强可能会导致系统响应变慢或出现超调。
例如,在温度控制中,如果误差一直存在,积分项会不断累积,使得控制量逐渐增大,直到温度达到设定值。
- 微分控制(D)
微分控制是根据误差的变化率(即当前误差与上一时刻误差的差值)与一个微分系数相乘来计算控制量。
微分控制的作用是预测误差的变化趋势,提前给出控制信号,从而减小超调量和提高系统的稳定性。
例如,如果温度上升速度很快,微分控制会产生一个较大的负控制量,以抑制温度的快速上升。
工作过程
首先,测量系统的实际输出值。
然后,计算实际输出值与设定值之间的误差。
分别计算比例、积分和微分三个部分的控制量:
比例控制量 = 比例系数 × 误差
积分控制量 = 积分系数 × 误差的累积和
微分控制量 = 微分系数 × 误差的变化率
将三个部分的控制量相加,得到总的控制量。
根据控制量来调整系统的输入,使系统的输出逐渐接近设定值。
外设应用
我们根据反射回的信息将小车运动分为以下几种情况
- 直行
此时五个红外对管反射回的信息为00100
1 | if(IPT[0]==0&&IPT[1]==0&&IPT[2]==1&&IPT[3]==0&&IPT[4]==0) |
- 左转90度
此时五个红外对管反射回的信息为11000或者11100
开始左转
1 | else if(IPT[0]==1&&IPT[1]==1&&IPT[3]==0&&IPT[4]==0) |
- 右转90度
此时五个红外对管反射回的信息为00011或者00111
开始右转
1 | else if(IPT[0]==0&&IPT[1]==0&&IPT[3]==1&&IPT[4]==1) |
- 向左偏一些
此时五个红外对管反射回的信息为01000
1 | else if(IPT[0]==0&&IPT[1]==1&&IPT[2]==0&&IPT[3]==0&&IPT[4]==0) |
- 向右偏一些
此时五个红外对管反射回的信息为00010
1 | else if(IPT[0]==0&&IPT[1]==0&&IPT[2]==0&&IPT[3]==1&&IPT[4]==0) |
- 掉头
此时五个红外对管反射回的信息为00000
1 | else if(IPT[0]==0&&IPT[1]==0&&IPT[2]==0&&IPT[3]==0&&IPT[4]==0) |
- 在遇见岔路时,选择右转
1 | else if(IPT[0]==1&&IPT[1]==1&&IPT[2]==1&&IPT[3]==1&&IPT[4]==1) |
使用直流电机作为动力源,通过电机驱动电路来控制电机的转速和方向。
通过控制左右两个电机的转速和方向,可以使小车实现前进、后退、转弯等动作。例如,当左侧电机转速高于右侧电机转速时,小车会向右转;当右侧电机转速高于左侧电机转速时,小车会向左转。
1 | void leftforward(void) |
使用PWM改变速度
1 |
|
结合任务二的部分,设计出简单的循迹算法
任务实现
1 |
|
视频:
任务五
并联比较型ADC概述
并联比较型ADC是通过并行比较多个电压输入值,将输入模拟信号转换为数字信号的一种方式,基本思想是同时将输入电压与多个参考电压进行比较,从而快速确定输入电压的数字表示。
各部分功能
- 比较器:主要功能是将输入的模拟信号与一组预设的参考电压进行比较。比较器输出高电平或低电平,表示输入信号高于或低于参考电压。
- 参考电压源:提供一组稳定的参考电压,通常是从0V到最高输入电压(例如,3.3V或5V)。这组参考电压可以是均匀分布的,帮助比较器进行比较。
- 编码器:根据比较器的输出,将比较结果转换为相应的二进制数字。如果比较器的输出表示有几个高电平,编码器就会确定输入信号的数值。
- 触发器:在完成比较后,触发器用来锁存比较器的结果,确保在ADC转换完成之前,不会受到输入信号变化的影响。
- 门电路:控制ADC的工作状态,例如使能和禁用ADC的功能。
工作原理
- 输入信号采样:首先,ADC从输入信号(模拟电压)进行采样。
- 并行比较:模拟信号会同时与多个参考电压进行比较,由多个比较器并行处理。
- 输出编码:根据比较器的结果,编码器将输出对应的数字信号。
- 结果输出:最终,转换后的数字信号被输出,通常是二进制格式,以供后续数字处理。