本设计是基于STM32单片机CO气体检测系统仿真设计(仿真+程序+原理图+讲解视频)
仿真图proteus 8.9
程序编译器:keil 5
编程语言:C语言
设计编号:C0045
1、本系统采用STM32内部ADC模块模拟MQ7传感器采集CO气体浓度。
2、通过液晶1602显示气体监测浓度和报警浓度。
3、可以通过按键设置报警值,气体超过设置值,电机启动,蜂鸣器报警,小于设定值,电机停止,蜂鸣器待机。
STM32驱动LCD1602显示代码
#include "bsp-lcd1602.h"
void LCD1602_GPIO_Config(void)
{
RCC_APB2PeriphClockCmd(LCD1602_CLK, ENABLE);
GPIO_InitTypeDef LCD1602_GPIOStruct;
LCD1602_GPIOStruct.GPIO_Mode = GPIO_Mode_Out_PP;
LCD1602_GPIOStruct.GPIO_Speed = GPIO_Speed_10MHz;
LCD1602_GPIOStruct.GPIO_Pin = LCD1602_E | LCD1602_RS | LCD1602_RW ;
GPIO_Init(LCD1602_GPIO_PORT,&LCD1602_GPIOStruct);
LCD1602_GPIOStruct.GPIO_Mode = GPIO_Mode_Out_OD;
LCD1602_GPIOStruct.GPIO_Pin = DB0 | DB1 | DB2 |DB3 | DB4 | DB5|
DB6 | DB7 ; //设置为开漏输出
GPIO_Init(LCD1602_GPIO_PORT,&LCD1602_GPIOStruct);
}
void LCD1602_WaitReady(void) //检测忙状态
{
uint8_t sta;
GPIOB->ODR =0x00FF;
RSO(0);
RWO(1);
EO(1);
SysTick_Delay_Us(1);
do{
sta=GPIO_ReadInputDataBit(LCD1602_GPIO_PORT,GPIO_Pin_7);
EO(0);
}while(sta);
}
void LCD1602_WriteCmd(uint8_t cmd) //写指令
{
LCD1602_WaitReady();
RSO(0);
RWO(0);
EO(0);
SysTick_Delay_Us(1);
EO(1);
LCD1602_GPIO_PORT->ODR &= (cmd|0xFF00);
EO(0);
SysTick_Delay_Us(400);
}
void LCD1602_WriteDat(uint8_t dat) //写数据
{
LCD1602_WaitReady();
RSO(1);
RWO(0);
SysTick_Delay_Us(30);
EO(1);
LCD1602_GPIO_PORT->ODR &=(dat|0xFF00);
EO(0);
SysTick_Delay_Us(400);
}
void LCD1602_SetCursor(uint8_t x, uint8_t y)
{
uint8_t addr;
if (y == 0) //由输入的屏幕坐标计算显示RAM的地址
addr = 0x00 + x; //第一行字符地址从0x00起始
else
addr = 0x40 + x; //第二行字符地址从0x40起始
LCD1602_WriteCmd(addr|0x80); //设置RAM地址
}
void LCD1602_ShowStr(uint8_t x, uint8_t y, uint8_t *str, uint8_t len)
{
LCD1602_SetCursor(x, y); //设置起始地址
while (len--) //连续写入len个字符数据
{
LCD1602_WriteDat(*str++);
}
}
//??1???
//x,y :????
//num:??(0~99)
//-----------------------------*/
void LCD_ShowNum(uint8_t x, uint8_t y,uint8_t num)
{
LCD1602_SetCursor(x, y); //设置起始地址
LCD_ShowChar(x,y,num+'0');
}
void LCD_ShowChar(uint8_t x, uint8_t y,uint8_t dat)
{
LCD1602_SetCursor(x, y); //设置起始地址
LCD1602_WriteDat(dat);
}
void LCD1602_Init(void)
{
LCD1602_GPIO_Config(); //开启GPIO口
LCD1602_WriteCmd(0X38); //16*2显示,5*7点阵,8位数据接口
LCD1602_WriteCmd(0x0C); //显示器开,光标关闭
LCD1602_WriteCmd(0x06); //文字不动,地址自动+1
LCD1602_WriteCmd(0x01); //清屏
}
主函数
#include "stm32f10x.h"
#include "bsp-lcd1602.h"
#include "delay.h"
#include "sys.h"
#include "adc.h"
#define KEY4 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_14) //读取按键K1
#define KEY5 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15) //读取按键K2
int th=10;
#define LED1 PAout(13)
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15; //配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置为上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化
}
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PC端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化
GPIO_SetBits(GPIOA,GPIO_Pin_13);
GPIO_SetBits(GPIOA,GPIO_Pin_12);
}
void KEY_Scan(void)
{
if(KEY4==0) //读取K1按键状态
{
delay_ms(10);
if(KEY4==0)
{
while(KEY4==0);
th++;
if(th>33) th=0;
}
}
if(KEY5==0) //读取K2按键状态
{
delay_ms(10);
if(KEY5==0)
{
while(KEY5==0);
if(th>0) th--;
}
}
}
int main(void)
{
int a,b,c,d;
int temp;
LED_Init();
delay_init(); //延时函数初始化
LCD1602_Init();
ADC1_GPIO_Config();
ADC_Config();
LCD1602_ShowStr(0,0,"co: ppm",8);
LCD1602_ShowStr(0,1,"AH: ppm",8);
KEY_Init();
while(1)
{
b=ADC_GetConversionValue(ADC1);
temp=b*10*(3.4/4096);
a=temp/10;
c=temp%10;
LCD_ShowNum(3,0,a);
LCD_ShowNum(4,0,c);
LCD_ShowNum(3,1,th/10);
LCD_ShowNum(4,1,th%10);
KEY_Scan();
if(temp>th) LED1=0;
else LED1=1;
}
}
STM32内部ADC驱动代码
#include "adc.h"
void ADC1_GPIO_Config(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1, ENABLE); //使能ADC1,GPIOC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PC4
}
void ADC_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;//ADC结构体变量//注意在一个语句快内变量的声明要放在可执行语句的前面,否则出错,因此要放在ADC1_GPIO_Config();前面
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //使能扫描
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC转换工作在连续模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//由软件控制转换,不使用外部触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//转换数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1;//转换通道为1
ADC_Init(ADC1, &ADC_InitStructure); //初始化ADC
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
//ADC1选择信道14,音序等级1,采样时间55.5个周期
// ADC_DMACmd(ADC1, ENABLE);//使能ADC1模块DMA
ADC_Cmd(ADC1, ENABLE);//使能ADC1
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// ADC_ResetCalibration(ADC1); //重置.(复位).ADC1校准寄存器
// while(ADC_GetResetCalibrationStatus(ADC1));//等待ADC1校准重置完成
// ADC_StartCalibration(ADC1);//开始ADC1校准
// while(ADC_GetCalibrationStatus(ADC1));//等待ADC1校准完成
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能ADC1软件开始转换
}
百度网盘下载链接: