• 基于STM32单片机一氧化碳(CO)气体监控系统proteus仿真设计


    本设计是基于STM32单片机CO气体检测系统仿真设计(仿真+程序+原理图+讲解视频)

    仿真图proteus 8.9

    程序编译器:keil 5

    编程语言:C语言

    设计编号:C0045

    主要功能:

    1、本系统采用STM32内部ADC模块模拟MQ7传感器采集CO气体浓度。

    2、通过液晶1602显示气体监测浓度和报警浓度。

    3、可以通过按键设置报警值,气体超过设置值,电机启动,蜂鸣器报警,小于设定值,电机停止,蜂鸣器待机。

    仿真图(提供源文件)

    仿真图

    程序(提供源文件源码)

    image-20220821114502098

    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);  //清屏
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106

    主函数

    #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;
    	}
    }
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    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软件开始转换
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    原理图(提供源文件仅供参考)

    image-20220821114602672

    资料清单

    在这里插入图片描述

    1. 常见使用问题及解决方法–必读!!!!
    2. 源程序
    3. proteus仿真
    4. 原理图
    5. 讲解视频
    6. 功能要求
      Altium Designer 软件资料
      filename.bat
      KEIL软件资料
      Proteus软件资料
      单片机学习资料
      目录清单.txt
      答辩技巧
      设计报告常用描述
      鼠标双击打开查找更多51 STM32单片机课程毕业设计.url

    百度网盘下载链接:

  • 相关阅读:
    对mysql的联合索引的深刻理解
    Java 面试题:强引用、软引用、弱引用、幻象引用有什么区别?
    【数据结构】广义表(列表)
    【R语言入门】开启R的会话并大步向前!
    【C++ Primer Plus学习记录】指针——指针和数字
    不改一行业务代码,飞书 iOS 低端机启动优化实践
    stable diffusion在建筑行业应用
    c++ vs2019 cpp20 规范,set源码分析
    学习笔记|ADC反推电源电压|扫描按键(长按循环触发)|课设级实战练习|STC32G单片机视频开发教程(冲哥)|第十八集:ADC实战
    已解决 TypeError: Fetch argument None has invalid type <class ‘NoneType‘>
  • 原文地址:https://blog.csdn.net/weixin_52733843/article/details/126449320