本章基于本人前面发的SPI驱动7针脚OLED屏幕文档。加入通过ADC模块对MQ135烟雾传感器的数值进行采样并在OLED上显示以及串口上打印。
一、MQ135烟雾传感器模块
正面:
接线:
烟雾模块 STM32开发板
AO —— PA0
VCC —— 3.3V
GND —— GND
二、ADC模块介绍:
ADC模块中文名为模拟/数字转换器,是12位逐次逼近型的模拟数字转换器,一般用于数值的采样,比如我最近在做一个示波器,那么就需要对信号进行采样,这就需要用到ADC模块。
将ADC模块与自己定义的引脚相连,再用该引脚去接入所要测试的地方,ADC模块便可以经过换算得到所要测试部位的电位。
三、ADC配置库函数解读:
1、初始化函数ADC_Init
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct)
功能:
typedef struct
{
uint32_t ADC_Mode; //将ADC配置为独立或操作双模式。
FunctionalState ADC_ScanConvMode;//执行转换Scan(多通道)或Single(单通道)模式,可设置为“ENABLE”或“DISABLE” */
FunctionalState ADC_ContinuousConvMode; //执行转换连续或单模。可设置为“ENABLE”或“DISABLE”
uint32_t ADC_ExternalTrigConv; //定义用于启动模拟的外部触发器对常规信道进行数字转换
uint32_t ADC_DataAlign; //指定ADC数据是左对齐还是右对齐。
uint8_t ADC_NbrOfChannel; //指定要转换的ADC通道的数量使用顺序器为常规通道组。取值范围为1 ~ 16
}ADC_InitTypeDef;
ADC结构体配置如下(本次为单通道模数转换):
ADC_InitTypeDef ADC_InitStructure; //定义ADC结构体
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC独立模式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件启动
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道数目
ADC_Init(ADC1, &ADC_InitStructure); //初始化ADC1外设
ADC_Cmd(ADC1, ENABLE); //使能ADC1
四、下面为ADC模块的整体代码,
ADC.c文件
#include "stm32f10x.h" // Device header
void Adc_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1通道时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA通道时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子这里为6分频
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA.0引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化gpioa
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//ADC1,通道0(GPIOA.0),采样顺序为1,采样周期为55.5个周期
ADC_InitTypeDef ADC_InitStructure; //定义ADC结构体
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC独立模式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件启动
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道数目
ADC_Init(ADC1, &ADC_InitStructure); //初始化ADC1外设
ADC_Cmd(ADC1, ENABLE); //使能ADC1
ADC_ResetCalibration(ADC1); //开启复位校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while (ADC_GetCalibrationStatus(ADC1) == SET); //等待校准结束
}
uint16_t Adc_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能软件转换功能
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待转换结束
return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}
ADC.h文件
#ifndef __ADC_H
#define __ADC_H
void Adc_init(void);
uint16_t Adc_GetValue(void);
#endif
五、串口打印数据
我们需要导入我们的USART函数
用printf串口打印接收到的数值我们需要在串口代码中加入串口重定向
int fputc(int ch,FILE *f)
{
Usart_SendByte(ch);
return ch;
}
main.c文件
uint16_t ADValue;
float Voltage;
int main(void)
{
Usart_Init();
Adc_init();
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
OLED_Init(); //初始化OLED
OLED_Clear(0); //清屏(全黑)
while (1)
{
ADValue = Adc_GetValue();
Voltage = (float)ADValue / 4095 * 3.3;
// GUI_ShowCHinese(0,20,16,"数值:",1);
// GUI_ShowNum(30,20,ADValue,6,16,1);//oled显示数字
printf("检测到的数值为 %d, 转换后的电压值为: %.1f V\n", ADValue, Voltage);
Delay_ms(1000);
}
}
6、7针脚OLED显示数值
显示中文(GUI_ShowCHinese)
x:中文字符串的起始x坐标
y:中文字符串的起始y坐标
hsize:中文字符串的大小
*str:中文字符串的起始地址
模式: 0-白底黑字,1-黑底白字
void GUI_ShowCHinese(u8 x,u8 y,u8 hsize,u8 *str,u8 mode)
{
while(*str!='\0')
{
if(hsize == 16)
{
GUI_ShowFont16(x,y,str,mode);
}
else if(hsize == 24)
{
GUI_ShowFont24(x,y,str,mode);
}
else if(hsize == 32)
{
GUI_ShowFont32(x,y,str,mode);
}
else
{
return;
}
x+=hsize;
if(x>WIDTH-hsize)
{
x=0;
y+=hsize;
}
str+=2;
}
}
显示数值(GUI_ShowNum)
x: 数字的开始坐标x
Y: 数字的起始Y坐标
num: (0 ~ 4294967295)
Len: 显示号的长度
大小: 显示编号的大小
模式: 0-白底黑字,1-黑底白字
void GUI_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 Size,u8 mode)
{
u8 t,temp;
u8 enshow=0,csize;
if(Size == 16)
{
csize = Size/2;
}
else if(Size == 8)
{
csize = Size/2+2;
}
else
{
return;
}
for(t=0;t<len;t++)
{
temp=(num/mypow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
GUI_ShowChar(x+csize*t,y,' ',Size,mode);
continue;
}else enshow=1;
}
GUI_ShowChar(x+csize*t,y,temp+'0',Size,mode);
}
}
main.c
int main(void)
{
Usart_Init();
Adc_init();
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
OLED_Init(); //初始化OLED
OLED_Clear(0); //清屏(全黑)
while (1)
{
ADValue = Adc_GetValue();
Voltage = (float)ADValue / 4095 * 3.3;
GUI_ShowCHinese(0,20,16,"数值:",1);
GUI_ShowNum(30,20,ADValue,6,16,1);//oled显示数字
// printf("检测到的数值为:%d 电压值为:%.1fV\n", ADValue, Voltage);
Delay_ms(1000);
}
}