0经验自己做网站,专业网站建设 公司,浙江网站建设推广公司哪家好,一般通过 什么意思文章目录 需求一、ADC概要二、实现流程1.开时钟#xff0c;分频#xff0c;配IO2.配置ADC工作模式3.配置通道4.复位校准5.数值的获取 三、需求的实现总结 需求
通过ADC转换实现光照亮度的数字化测量#xff0c;最后将实时测量的结果打印在串口上。 一、ADC概要 ADC全称是A… 文章目录 需求一、ADC概要二、实现流程1.开时钟分频配IO2.配置ADC工作模式3.配置通道4.复位校准5.数值的获取 三、需求的实现总结 需求
通过ADC转换实现光照亮度的数字化测量最后将实时测量的结果打印在串口上。 一、ADC概要 ADC全称是Analog-to-Digital Converter模数转换器一般我们把模拟信号(Analog signal) 用A来进行简写数字信号(digital signal) 用D来表示。 自然界中绝大部分都是模拟信号例如压力或温度的测量为了方便储存处理和传输我们会通过ADC把模拟信号转化成数字形式给计算机处理。将模拟转换成数字的形式有两个步骤采样和量化。 本例中就是将光照亮度这种模拟量转换为具体的数字量。
本次使用的ADC
二、实现流程
1.开时钟分频配IO
先打开原理图找到该光敏电阻的位置。 由该电路可知VAL测量的是该光敏电阻的分压而随着光照的变化该光敏电阻的电压也会发生实时的波动。 此时我们就利于该光敏电压的变化来实现需求。 先找到CPU上对应的引脚 由上图可知该模块对应的引脚为PA5ADC为ADC12_IN5代表该引脚PA5是ADC1/2的通道5。 此时我们就开GPIOA的时钟和ADC1的通道1,2都行无所谓 代码如下 RCC-APB2ENR | 0x019;//ADC1通道RCC-APB2ENR | 0x012;//使能GPIOA下面就要进行分频了由于本次使用的ADC的特征为12分辨率而APB2所传输的频率为72M所以此时我们要进行6分频72 ÷ 6 12 RCC-CFGR ~(0x0314);RCC-CFGR | (0x0214);//6分频最后进行PA5引脚的模式配置由于要获得该引脚的电压值而该电压值为动态变化的模拟量所以此处要将模式置为模拟输入模式0000
GPIOA-CRL ~(0x0F20);//配置成模拟输入2.配置ADC工作模式
首先打开手册找ADC1的控制寄存器CR1CR2一个一个查看看是否需要配置。 一般常用的是第8位扫描模式 不过此处只传输光照一个变量所以可以不开置零就行。 双模式选择也是必要的此处选独立模式就行因为只用这一个ADC1。 到这里ADC1的CR1寄存器的基本配置就算完成了。 下面来看ADC1的CR2寄存器。 先来看第20位规则通道的外部触发转换模式。规则通道组每转换一次代表着ADC1把数据传输到DR规则组通道数据寄存器上该寄存器为16位并且每传输一次数据就会被覆盖一次。 此处我们选择开启1使用外部时间启动转换 再来看19-17位规则通道组转换的外部触发条件。 我们这里选择111SWSTART软件触发因为是通过软件代码置位来触发。 第十一位数据对齐的模式要选择为右对齐方便后续操作。 第一位的连续转换可开可关因为只有光照一个量。 最后使能一下第0位开启ADC并启动转换。 //3、配置ADC的工作模式ADC1-CR1 ~(0x0F16);//独立模式ADC1-CR1 ~(0x018);//不开扫描ADC1-CR2 | 0x0120;//选择开启外部触发ADC1-CR2 | 0x0717;//触发方式swsatrt(软件触发)ADC1-CR2 ~(0x0111);//选择数据右对齐ADC1-CR2 ~(0x011);//关闭连续转换ADC1-CR2 | 0x010;//ADC使能3.配置通道
由于该引脚PA5对应的是ADC12_IN5所以我们只需要配置通道5即可。 配置通道在ADC规则序列寄存器和ADC采样时间寄存器中。 先找到SQR1寄存器 ADC规则序列寄存器负责通道数量的选择共有16个由于我们只用通道5所以此时我们将L配置成0000只配只配一个通道。 接下来配置我们选的SQ1通道将其配成通道0x05。 最后配置一下采样周期周期越大越准所以我选择了111:239.5周期。 //配置一个通道通道5第一个转换采样周期最大239.5ADC1-SQR1 ~(0x0F20);//规则组通道只转换一个配置通道数量//具体某个通道的配置ADC1-SQR3 ~(0x1F0);//0-5位清0ADC1-SQR3 | 0x050;//选择第一个转换通道5ADC1-SMPR2 | 0x0715;//采样周期最大239.54.复位校准
复位校准可有可无不过为了更加保险我还是加上了。 总共校准了两次校准位在CR2寄存器的第三位。 每次校准后会自动置位0所以此处while(1)等待非0,若为1就等待为0就校准完成继续往下执行。 ADC1-CR2 | 0x013;//启动复位校准//等待复位校准结束while((ADC1-CR2(0x013))!0)//判断寄存器的位3是不是等于1{}ADC1-CR2 | 0x012;//启动AD校准//等待AD校准结束while((ADC1-CR2(0x012))!0)//判断寄存器的位2是不是等于1,是1就等待{}5.数值的获取
对于数值的获取我是单独写了个函数来执行放便主函数调用并发送给串口。 想要获取数据就要让ADC的CR2寄存器的第22位置1转换一下。 每转换一次就代表着ADC1把数据传输到DR规则组通道数据寄存器上该寄存器为16位并且每传输一次数据就会被覆盖一次。 所以此时我们让ADC的CR2寄存器的第22位置为1
那么什么时候代表转换完了此时就要查看ADC的状态寄存器SR了 可以看到每一次转换结束时ADC_SR寄存器的第一位就会置1并且不用我们去清零每当我们去ADC_DR读取数据时就会自动清除。 那么此时我们就可判断转换结束位的0,1来进行数据的读取了。 最后将读取到的光照强度数据打印即可。之前已经给printf重定向了会自动打印到串口中
void GetLightValue()
{uint16_t Light0;//让规则通道转换一次ADC1-CR2 | 0x0122;while((ADC1-SR(0x011))0)//判断寄存器的位2是不是等于1是0就等待转换完成{}Light ADC1-DR; //读规则组通道数据寄存器printf(光照强度参数 %d \r\n,Light);
}
三、需求的实现
关键代码如下 main.c
#include stm32f10x.h
#include usart.h
#include stdio.h
#include delay.h
#include string.h
#include pwm.h
#include adc.hint main()
{NVIC_SetPriorityGrouping(5);//两位抢占两位次级Usart1_Config(); SysTick_Config(72000);RGBpwm_Config();uint8_t cai_count0;uint16_t cont0;Adc_Config();while(1){ if(ledcnt[0]ledcnt[1]){//过去500msledcnt[0]0;GetLightValue();}}
}adc.c
#include ADC.hvoid Adc_Config(void)
{//PA5//1、设置ADC的时钟(开时钟和时钟分频6分频)RCC-APB2ENR | 0x019;//ADC1通道RCC-APB2ENR | 0x012;//使能GPIOARCC-CFGR ~(0x0314);RCC-CFGR | (0x0214);//6分频//2、配置IO模式模拟输入GPIOA-CRL ~(0x0F20);//配置成模拟输入//3、配置ADC的工作模式ADC1-CR1 ~(0x0F16);//独立模式ADC1-CR1 ~(0x018);//不开扫描ADC1-CR2 | 0x0120;//选择开启外部触发ADC1-CR2 | 0x0717;//触发方式swsatrt(软件触发)ADC1-CR2 ~(0x0111);//选择数据右对齐ADC1-CR2 ~(0x011);//关闭连续转换ADC1-CR2 | 0x010;//ADC使能//配置一个通道通道5第一个转换采样周期最大239.5ADC1-SQR1 ~(0x0F20);//规则组通道只转换一个配置通道数量//具体某个通道的配置ADC1-SQR3 ~(0x1F0);//0-5位清0ADC1-SQR3 | 0x050;//选择第一个转换通道5ADC1-SMPR2 | 0x0715;//采样周期最大239.5ADC1-CR2 | 0x013;//启动复位校准//等待复位校准结束while((ADC1-CR2(0x013))!0)//判断寄存器的位3是不是等于1{}ADC1-CR2 | 0x012;//启动AD校准//等待AD校准结束while((ADC1-CR2(0x012))!0)//判断寄存器的位2是不是等于1,是1就等待{}
}void GetLightValue()
{uint16_t Light0;//让规则通道转换一次ADC1-CR2 | 0x0122;while((ADC1-SR(0x011))0)//判断寄存器的位2是不是等于1是0就等待转换完成{}Light ADC1-DR; //读规则组通道数据寄存器printf(光照强度参数 %d \r\n,Light);
}
adc.h
#ifndef _ADC_H_
#define _ADC_H_
#include stm32f10x.h
#include stdio.h
void GetLightValue();void Adc_Config(void);
#endif
delay.c
#include stm32f10x.h
#include delay.huint32_t systicktime0;uint16_t ledcnt[2]{0,1000};//500ms 每个任务执行的时间
uint16_t led2cnt[2]{0,2000};//700ms
uint16_t keycnt[2]{0,10};//10ms检测一次
void SysTick_Handler(void)//1ms调用一次
{//不需要清中断挂起位systicktime;ledcnt[0];led2cnt[0];keycnt[0];
}void Delay_ms(uint32_t time)
{uint32_t nowtime systicktime;while(systicktime timenowtime);
}void Delay_nus(uint32_t time)
{uint32_t i0;for(i0;itime;i){delay1us();}
}void Delay_nms(uint32_t time)
{uint32_t i0;for(i0;itime;i){Delay_nus(1000);//延时1ms}
}
delay.h
#ifndef _DELAY_H_
#define _DELAY_H_
#include stm32f10x.h#define delay1us() {__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}extern uint16_t ledcnt[2];
extern uint16_t led2cnt[2];
extern uint16_t keycnt[2]; void Delay_nus(uint32_t time);
void Delay_ms(uint32_t time);
void Delay_nms(uint32_t time);
#endif 总结
1.先看该光敏电阻的电路图分析如何获取光照的数值。 2.想到可以通过ADC转换得到光照的树数值开始学习ADC的知识。 3.先看ADC的功能描述然后开时钟分频配IO。 4.看手册中的ADC的控制寄存器一个一个查看看看究竟需要配置那些。 5.看该引脚的ADC是那个通道的开始配置通道。 6.都配置完后进行复位校准和数据获取函数的编写。 7.最后在主函数按照需求调用即可。