先来看看本次实验的结果吧:stm32点电压测量范围为0-3.3v,数值为:0-4095
来看看这个工程的文件布局吧:
实现adc功能总共分为六步:
第一步:开始rcc时钟,包括adc和gpio的时钟,adcclk的分频器也需要配置一下。
第二步:配置gpio,把需要用的gpio配置成模拟输入的模式
第三步:配置多路开关,把左边的通道接入规则组列表里
第四步:配置adc转换器,用结构体配置,一大块的参数。
第五步:打开adc_cmd()开启adc。
第六步:校准adc
接着来学习一下adc相关的库函数:(看起来好像有点乱,后面有截图)
void rcc_adcclkconfig(uint32_t rcc_pclk2); 用来配置adcclk分频器的 void adc_cmd(adc_typedef* adcx, functionalstate newstate); 这个是用来给adc上电的函数 void adc_dmacmd(adc_typedef* adcx, functionalstate newstate); 用来开启dma输出信号的 void adc_itconfig(adc_typedef* adcx, uint16_t adc_it, functionalstate newstate); 中断输出控制 void adc_resetcalibration(adc_typedef* adcx); 复位校准 flagstatus adc_getresetcalibrationstatus(adc_typedef* adcx); 获取复位校准状态 void adc_startcalibration(adc_typedef* adcx); 开始校准 flagstatus adc_getcalibrationstatus(adc_typedef* adcx); 获取开始校准状态 void adc_softwarestartconvcmd(adc_typedef* adcx, functionalstate newstate); adc软件开始转换控制 软件触发的函数 flagstatus adc_getsoftwarestartconvstatus(adc_typedef* adcx); adc获取软件开始转换状态 flagstatus adc_getflagstatus(adc_typedef* adcx, uint8_t adc_flag); 获取转换完成标志位状态,判断eoc标志位是不是置1了。 void adc_discmodechannelcountconfig(adc_typedef* adcx, uint8_t number); 间隔几个通道采集信
void adc_discmodecmd(adc_typedef* adcx, functionalstate newstate); 是否启用间隔模式 void adc_regularchannelconfig(adc_typedef* adcx, uint8_t adc_channel, uint8_t rank, uint8_t adc_sampletime); 规则组通道配置 void adc_externaltrigconvcmd(adc_typedef* adcx, functionalstate newstate); adc 外部触发转换控制,就是是否允许外部触发转换 uint16_t adc_getconversionvalue(adc_typedef* adcx); adc获取转换值 uint32_t adc_getdualmodeconversionvalue(void); adc获取双模式转换值,这个是双adc模式读取转换结果 void adc_analogwatchdogcmd(adc_typedef* adcx, uint32_t adc_analogwatchdog); //是否启动看门口 void adc_analogwatchdogthresholdsconfig(adc_typedef* adcx, uint16_t highthreshold, uint16_t lowthreshold); //配置高低阈值 void adc_analogwatchdogsinglechannelconfig(adc_typedef* adcx, uint8_t adc_channel); //配置看门的通道 配置模拟看门狗的三个函数 void adc_tempsensorvrefintcmd(functionalstate newstate); //adc温度传感器内部参考电压控制,用来开启内部通道 flagstatus adc_getflagstatus(adc_typedef* adcx, uint8_t adc_flag); //获取标志位状态 void adc_clearflag(adc_typedef* adcx, uint8_t adc_flag); // 清楚标志位状态 itstatus adc_getitstatus(adc_typedef* adcx, uint16_t adc_it); //获取中断状态 void adc_clearitpendingbit(adc_typedef* adcx, uint16_t adc_it); //清楚中断挂起位
接下来就是每个文件的源码了:
myadc.c文件:
#include "stm32f10x.h" // device header
void myadc_init(void)
{
//第一步:开始rcc时钟,包括adc和gpio的时钟,adcclk的分频器也需要配置一下。
rcc_apb2periphclockcmd(rcc_apb2periph_adc1, enable); //开启adc1的时钟
rcc_apb2periphclockcmd(rcc_apb2periph_gpioa, enable); //开启gpioa的时钟
rcc_adcclkconfig(rcc_pclk2_div6); // adc的时钟选择6分频,也就是72m/6=12m
//第二步:配置gpio,把需要用的gpio配置成模拟输入的模式
gpio_inittypedef gpio_initstruct; //gpio初始化的结构体
gpio_initstruct.gpio_mode = gpio_mode_ain; // 模式为模拟输入
gpio_initstruct.gpio_pin = gpio_pin_0; // 初始化端口0
gpio_initstruct.gpio_speed = gpio_speed_50mhz; //端口频率50m
gpio_init(gpioa, &gpio_initstruct); // gpioa初始化
//第三步:配置多路开关,把左边的通道接入规则组列表里
adc_regularchannelconfig(adc1, adc_channel_0, 1, adc_sampletime_28cycles5); //adc1规则配置(adc1,通道1,列表1,转换时间28.5个时钟(12m))
//第四步:配置adc转换器,用结构体配置,一大块的参数。
adc_inittypedef adc_initstruct; //adc初始化结构体
adc_initstruct.adc_continuousconvmode = disable; //连续转换模式:关闭
adc_initstruct.adc_dataalign = adc_dataalign_right; // 数据对齐:右对齐
adc_initstruct.adc_externaltrigconv = adc_externaltrigconv_none; //adc中断触发:空,也就是软件触发
adc_initstruct.adc_mode = adc_mode_independent; // adc模式:独立模式
adc_initstruct.adc_nbrofchannel = 1; //规则组中的通道数:1
adc_initstruct.adc_scanconvmode = disable; //扫描模式:关闭
adc_init(adc1, &adc_initstruct); //adc初始化
//第五步:打开adc_cmd()开启adc。
adc_cmd(adc1, enable); // adc开启
//第六步:校准adc
adc_resetcalibration(adc1); // 复位校准adc
while(adc_getresetcalibrationstatus(adc1) == set); // 等待校准标志位置0
adc_startcalibration(adc1); // 开始复位校准adc
while(adc_getcalibrationstatus(adc1) == set); // 等待开始校准结束标志位置0
}
uint16_t get_val(void)
{
adc_softwarestartconvcmd(adc1, enable); // 软件触发adc使能
while(adc_getflagstatus(adc1, adc_flag_eoc) == reset); // 等待获取eoc标志位置1
return adc_getconversionvalue(adc1); // 返回adc转换的结果值
}
myadc.h文件:
#ifndef __myadc_h
#define __myadc_h
void myadc_init(void);
uint16_t get_val(void);
#endif
主函数main.c文件:
#include "stm32f10x.h" // device header
#include "delay.h"
#include "oled.h"
#include "ad.h"
uint16_t advalue; //定义ad值变量
float voltage; //定义电压变量
int main(void)
{
/*模块初始化*/
oled_init(); //oled初始化
ad_init(); //ad初始化
/*显示静态字符串*/
oled_showstring(1, 1, "advalue:");
oled_showstring(2, 1, "voltage:0.00v");
while (1)
{
advalue = ad_getvalue(); //获取ad转换的值
voltage = (float)advalue / 4095 * 3.3; //将ad值线性变换到0~3.3的范围,表示电压
oled_shownum(1, 9, advalue, 4); //显示ad值
oled_shownum(2, 9, voltage, 1); //显示电压值的整数部分
oled_shownum(2, 11, (uint16_t)(voltage * 100) % 100, 2); //显示电压值的小数部分
delay_ms(100); //延时100ms,手动增加一些转换的间隔时间
}
}
还有一个oled的代码就不展示了,没有的可以在之前的博文中找到,都有公布过,自己挨片的看就能找到的,编译后写入到stm32中就能看到实验结果了,调整电位器就能看到电压和数值的变化,电位器中间抽头接a0,另外两个头中的一个接3.3v电源,这就是整个的接线图了。
发表评论