提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

本文章为个人单片机课程大作业,代码都是自己写的,只是记录自己的学习过程,不做任何商用。

目录

单片机大作业:

一、使用仪器、材料

二、步骤

1.接线

2.写代码

main.c:

ADC.h:

key.h:

1602.H:

3.烧录

三、实验结果

四、总结


单片机大作业:

基于ATMEGA16单片机,MQ-3酒精传感器,LCD1602液晶显示的酒精浓度检测阈值报警仪
功能:
1.将MQ-3传感器模块靠近酒精气体,LCD1602显示屏上显示酒精数值Alcohol  mg/L;
2.按键s1设置阈值Set加一,按键s2调节阈值Set减一,按键s3调节阈值Set加十,按键s4调节阈值Set减十;
3.当MQ-3测得酒精浓度数值大于等于阈值(Set)时,蜂鸣器持续响;当MQ-3测得酒精浓度数值小于阈值(Set)时,蜂鸣器停止响;
4.按键每按一下,阈值(Set)改变的同时蜂鸣器响一声。

一、使用仪器、材料

硬件:ATMega16单片机,LCD1602液晶显示,MQ-3酒精传感器,蜂鸣器,杜邦线若干

软件:ICCV7 for AVR(用于编译),Visual Studio Code(用于写代码),progisp.exe (用于烧录)

二、步骤

1.接线

将ATMega16单片机,MQ-3传感器,lcd1602,蜂鸣器用杜邦线连接好;

接线方式:

ATMEGA16 PA0 ---- MQ-3 A0

ATMEGA16 VCC ---- MQ-3 VCC

ATMEGA16 GND ---- MQ-3 GND

备注:MQ-3 D0 未接线(可以不接)

ATMEGA16 ---- LCD1602

ATMEGA16 PD4 ---- 蜂鸣器 I/O

ATMEGA16 VCC ---- 蜂鸣器 VCC

ATMEGA16 GND ---- 蜂鸣器 GND

2.写代码

代码包含.c文件main.c,头文件ADC.h,key.h, 1602.H,把他们放到一个project里面,选择单片机为ATMega16,编译,生成hex文件。

main.c:

#include <iom16v.h>
#include <macros.h>
#include "ADC.h"
#include "math.h"
#include "key.h"
void io_init(void)//IO口初始化
{DDRC = 0xFF; //LCD端口输出PORTC = 0xff;DDRD = 0xf0;  //输出(1111 0000),PD0,PD1,PD2三位控制LCD,PD4控制蜂鸣器PORTD = 0xFF; //输出高电平DDRB = 0x00; //按钮输入口(1110 0000)PORTB = 0xFF;PORTA = 0XFF; //设置AD采集端口ADC为输入,本项目用PA0作为ADC输入DDRA = 0X00;
}void DisplayAlcohol(uchar Line)//显示MQ3酒精浓度
{float Vrl=0;Vrl=(adc_data*5.0)/1024.0;//将PA0模拟输出转换为电压值adc_data=pow((11.5428*35.904*Vrl)/(25.5-5.1*Vrl),0.6549);//ppm即计算后的adc_dataten_4 = (adc_data) / 1000;ten_3 = (adc_data) / 100%10;ten_2 = (adc_data) / 10%10;ten_1 = adc_data%10;ten_1 += 0x30;//转换成这个数字对应的ASCII码,作用跟  ten_1 += '0'  相同ten_2 += 0x30;ten_3 += 0x30;ten_4 += 0x30;WriteNum(Line, 8, (ten_4));//在第Line行,第八列lcd开始显示adc_data的千位数WriteNum(Line, 9, (ten_3));WriteNum(Line, 10, (ten_2));WriteNum(Line, 11, (ten_1));
}void DisplaySetAlcohol(uchar Line)//显示设定酒精(阈值)浓度
{ten_4 = (SetAlcohol) / 1000;ten_3 = (SetAlcohol) / 100%10;ten_2 = (SetAlcohol) / 10%10;ten_1 = SetAlcohol%10;ten_1 += 0x30;ten_2 += 0x30;ten_3 += 0x30;ten_4 += 0x30;WriteNum(Line, 8, (ten_4));WriteNum(Line, 9, (ten_3));WriteNum(Line, 10, (ten_2));WriteNum(Line, 11, (ten_1));
}void main(void)//主函数
{uint ad1,ad2;io_init();//io初始化LcdInit();//lcd初始化WriteChar(1, 0, 16, Alcohol);//显示数组ALcohol,即显示lcd第一行的  Alcohol:    mg/LWriteChar(2, 0, 16, Set);while (1){key_scan();//按键扫描函数get_AD();//ADC初始化函数adc_data=ad_cat();DisplayAlcohol(1);//将测得的酒精浓度数值显示在lcd第一行delay(100);DisplaySetAlcohol(2);//将酒精浓度阈值数值显示在lcd第二行delay(100);if(adc_data>=SetAlcohol)//测得酒精浓度大于阈值{//delay(100);PORTD &= ~(1 << PD4); //(1110 1111),低电平蜂鸣器响}if(adc_data<SetAlcohol){PORTD |= BIT(4); //(1111 1111),高电平蜂鸣器关}}
}

ADC.h:

#include "1602.H"
#define uchar unsigned char
#define uint unsigned int
uchar Alcohol[] = {"Alcohol:    mg/L"};//lcd第一行要显示的数组
uchar Set[] = {"Set    :    mg/L"};//lcd第二行要显示的数组
uchar ten_1, ten_2, ten_3,ten_4;//个十百千位要显示的数字
uint adc_data, adc_l, adc_h;
void get_AD(void)//ADC初始化
{ADMUX = 0x40;//ADC0,ADCSRA = 0x00;//关掉ADCADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADFR) | 0x07;//128分频,连续转换s_ms(500);//延时adc_l = ADCL;adc_h = ADCH;adc_data = adc_h << 8 | adc_l;adc_data = adc_data >> 1;adc_data -= 35;
}unsigned int ad_cat(void)//电压采集函数
{unsigned int t1,t2;ADCSRA = 0X00;//disable ADCADMUX=0x00;//ref  左对齐  ADC0ACSR = 0x80;//使能ADC可用,不用修改ADCSRA|=BIT(ADEN); //ADC使能          ADCSRA|=BIT(ADSC); //开始转换          while(!(ADCSRA&(BIT(ADIF))));//ADIF置一,adc转换结束时,跳出循环ADCSRA&=~BIT(ADIF);//清零t1 = (unsigned int)ADCL;t2 = (unsigned int)ADCH;t2 = (t2<<8)+t1;//高位左移8位加上低位return t2;
}   

key.h:

unsigned int i=0,SetAlcohol=400;
void delay(uint time)//延时函数
{uint i,j;for(i=0;i<254;i++){for(j=0;j<time;j++){;}}
}void key_scan(void)//按键函数,实现按键每按一下阈值变化的同时蜂鸣器响一声
{if((PINB&(1<<PB0))==0)     //按键PB0,s1{if(SetAlcohol<1666){SetAlcohol++;} delay(500);PORTD &= ~(1 << PD4);}if((PINB&(1<<PB1))==0)     //按键PB1,s2{if(SetAlcohol>0){SetAlcohol--;}delay(500);PORTD&=~(1<<PD4);}if((PINB&(1<<PB2))==0)     //按键PB2,s3{if(SetAlcohol<1666){SetAlcohol+=10;} delay(500);PORTD&=~(1<<PD4);}    if((PINB&(1<<PB3))==0)     //按键PB3,s4{if(SetAlcohol>=10){SetAlcohol-=10;}delay(500);PORTD&=~(1<<PD4);}
}

1602.H:

#define uchar unsigned char
#define uint unsigned int #define RS 7
#define RW 6
#define EN 5void s_ms(uint ms)
{for(;ms>1;ms--);
}   //查忙
void busy(void)
{uchar temp;s_ms(500);PORTD&=~(1<<RS);    //RS=7s_ms(500);PORTD|=(1<<RW);     //RW=6s_ms(500);while(temp){PORTD|=(1<<EN); //EN=5s_ms(500);DDRC=0x00;      //A口变输入PORTC=0xff;     //上拉使能s_ms(500);temp = PINC&0x80;    //读取C口s_ms(500);      DDRC=0xff;      PORTC=0xff;        //C口变输出s_ms(500);PORTD&=~(1<<EN);   //EN=0s_ms(500);}
}//写指令
void writecom(uchar com)
{busy();s_ms(500);PORTD&=~(1<<RS);   //RS=7s_ms(500);PORTD&=~(1<<RW);   //RW=6s_ms(500);PORTD|=(1<<EN);    //EN=5s_ms(500);PORTC = com;       //输出指令s_ms(500);PORTD&=~(1<<EN);   //EN=0s_ms(500);
}//1602初始化
void    LcdInit(void)
{writecom(0x38);s_ms(1000);writecom(0x01);s_ms(10000);s_ms(1000);s_ms(1000);s_ms(1000);s_ms(1000);s_ms(1000);s_ms(1000);writecom(0x02);s_ms(1000);writecom(0x06);s_ms(1000);writecom(0x0c);s_ms(1000);writecom(0x38);   s_ms(1000);
}   //写数据
void    writedata(uchar data)
{busy();s_ms(500);PORTD|=(1<<RS);   //RS=7s_ms(500);PORTD&=~(1<<RW);   //RW=6s_ms(500);PORTD|=(1<<EN);    //EN=5s_ms(500);PORTC = data;      //输出数据s_ms(500);PORTD&=~(1<<EN);   //EN=0s_ms(500);
}//读数据
uchar   readdata(void)
{uchar temp;busy();s_ms(500);PORTD|=(1<<RS);  //RS=7s_ms(500);PORTD|=(1<<RW);  //RW=6s_ms(500);PORTD|=(1<<EN);  //EN=5s_ms(500);DDRC=0x00;       //A端口变输入s_ms(500);temp = PINC;     //读A端口s_ms(500);DDRC=0xff;       //A端口变输出s_ms(500);PORTD&=~(1<<EN); //EN=0s_ms(500);return temp;
}//=================================================
// 描述: 写LCD内部CGRAM函数
// 入口: ‘num’要写的数据个数
//        ‘pbuffer’要写的数据的首地址
// 出口: 无
//================================================
void    WriteCGRAM(uint num, const uint *pBuffer)
{uint   i,t;writecom(0x40);PORTD|=(1<<RS);PORTD&=~(1<<RW);for(i=num;i!=0;i--){t = *pBuffer;PORTD|=(1<<EN);PORTC = t;PORTD&=~(1<<EN);                pBuffer++;}}//=================================================
//描述:写菜单函数,本程序使用的LCD规格为 16 * 2
//入口:菜单数组首地址
//出口:无
//=================================================
void    WriteMenu(const uchar *pBuffer)
{uchar  i,t;writecom(0x80);   //数据地址PORTD|=(1<<RS);PORTD&=~(1<<RW);s_ms(50);for(i=0;i<16;i++){t = *pBuffer;PORTC = t;PORTD|=(1<<EN);s_ms(50);PORTD&=~(1<<EN);               pBuffer++;}writecom(0xC0);PORTD|=(1<<RS);PORTD&=~(1<<RW);s_ms(50);  for(i=0;i<16;i++){t = *pBuffer;PORTC = t;PORTD|=(1<<EN);s_ms(50);PORTD&=~(1<<EN);             pBuffer++;}
}
//====================================================
// 描述:在任意位置写数字函数
// 入口:’row‘表示要写数字所在的行地址,只能为1或2
//       ’col‘表示要写数字所在的列地址,只能为0--15
//       ‘num’表示要写的数字,只能为0--9
// 出口:无
//===================================================
void WriteNum(uchar row,uchar col,uchar num)
{if (row == 1)    row = 0x80 + col;else row = 0xC0 + col;writecom(row);PORTD|=(1<<RS);s_ms(500);PORTD&=~(1<<RW);s_ms(500);PORTC = num;s_ms(500);PORTD|=(1<<EN);s_ms(500);PORTD&=~(1<<EN);    s_ms(500);
}
//================================================================
// 描述:在任意位置写任意多个字符
// 入口:’row‘要写的字符所在的行,只能为1或2;
//       ‘col’要写的字符所在的列,只能为0---15
//       ‘num’要写字符的个数
//       ‘pbuffer’要写字符的首地址
//==================================================================
void    WriteChar(uchar row,uchar col,uint num,uchar *pBuffer)
{uchar i,t;if (row == 1)  row = 0x80 + col;else row = 0xC0 + col;writecom(row);PORTD|=(1<<RS);s_ms(500);PORTD&=~(1<<RW);s_ms(500);for(i=num;i!=0;i--){t = *pBuffer;s_ms(500);PORTC = t;s_ms(500);PORTD|=(1<<EN);s_ms(500);PORTD&=~(1<<EN);        s_ms(500);      pBuffer++;}}

3.烧录

找到生成的hex文件,将单片机连接上USBISP线后,通过烧录软件烧录到接好线的单片机中,观察实验结果。

三、实验结果

当MQ-3传感器原理酒精时,也就是只暴露在正常的空气中时,LCD1602显示  Alcohol:13mg/L

标题MQ-3远离酒精,只暴露在普通的空气中

当MQ-3传感器原理酒精时,也就是只暴露在正常的空气中时,LCD1602显示  Alcohol:1666mg/L

备注:ATMega的ADC模块最高只有十位,此时输入的电压值有限,因此此时显示的有最大值,至于为什么是1666,我也没花时间去弄明白。有兴趣的小伙伴可以自己慢慢钻研哈。其实将传感器慢慢离酒精远一点显示屏上面的数值会变化,这里不方便放图片了。

MQ-3传感器靠近酒精

MQ-3传感器靠近酒精

下面那一行Set的数值(也就是自己设置的酒精浓度阈值)可以通过按按键改变:

用按键修改Set值

四、总结

没啥总结的,就是有几点需要注意:

线路一定不要接错;

MQ-3模块一开始工作的时候可以预热一会,这样测出来更精准(这个我也是看到别人说的);

MQ-3模块工作的时候会发热,但是温度如果烫手了的话应该就是出问题了。

最后,如果是要自己学习单片机的话,建议不要用这个板子,真不好用。

祝各位不负青春!

基于ATMEGA16单片机,MQ-3酒精传感器,LCD1602液晶显示的酒精浓度检测阈值报警仪相关推荐

  1. 模块称重51单片机电子秤称重压力检测阈值报警仪系统 源码+原理图仿

    HX711模块称重51单片机电子秤称重压力检测阈值报警仪系统 源码+原理图仿真(文件,文件,文件) 本系统由STC89C52单片机.LCD1602液晶显示.HX711称重传感器. 蜂鸣器报警.按键及电 ...

  2. 基于ATmega16单片机和GPS的多用途定位仪设计

    目录 摘要 I Abstract II 第1章绪论 1 1.1 课题研究的背景及意义 1 1.2国内外研究现状 1 1.2.1 外国研究发展现状 1 1.2.2国内研究发展现状 2 1.3课题研究技术 ...

  3. 基于ATMEGA16单片机的空调控制器

    点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87853101 源码获取 主要内容: ...

  4. 基于51单片机和红外漫反射传感器的久坐提醒神器(番茄钟)的设计

    一.背景介绍 我们工作久了,久坐导致的毛病就显现出来了,腰酸背痛颈椎疼,最近看到利用番茄钟工作法挺好,工作25分钟,休息5分钟,既能调整工作节奏,避免精力过分消耗,也能避免久坐导致的身体问题. 我刚开 ...

  5. 基于51单片机的时钟闹钟温度计LCD1602显示proteus仿真原理图PCB

    功能介绍: 0.本系统采用STC89C52作为单片机 1.LCD1602液晶实时显示时间/当前温度 2.按键可进行闹钟设置和温度上下限设置 3.到达闹钟时间或温度超过阈值范围,蜂鸣器报警 4.到达闹钟 ...

  6. 34、基于51单片机锂电池电压电流容量检测仪表LCD液晶显示 原理图PCB程序设计

    方案选择 单片机的选择 方案一:AT89C52是美国ATMEL公司生产的低电压,高性能CMOS型8位单片机,器件采用ATMEL公司的高密度.非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通 ...

  7. 98、基于51单片机锂电池电压电流容量检测仪表LCD液晶显示

    毕设帮助.开题指导.技术解答(有偿)见文末. 目录 摘要 一.硬件方案 二.设计功能 三.实物图 四.原理图 五.PCB图 六.部分程序源码 七.资料包括 摘要 锂离子电池是 1990年后逐渐发展起来 ...

  8. 70、基于STM32单片机的蓝牙智能热水器控制系统设计温度温控水温水位检测

    毕设帮助.开题指导.技术解答(有偿)见文末. 目录 摘要 一.硬件方案 二.设计功能 三.实物图 四.原理图 五.PCB图 六.硬件框图 七.程序源码 八.资料包括 摘要 随着社会的发展,人类科技的进 ...

  9. 基于C51单片机的万年历设计(LCD1602显示)

    C51单片机万年历设计 注:该程序基于普中科技C51 V2.2开发板设计,库函数和硬件资料均来自普中科技,侵删.main.c大部分为原创,如有雷同,纯属巧合. 名称:C51万年历. 硬件:以C51芯片 ...

最新文章

  1. bar图设置距离 python_python画图设置坐标轴的位置及角度及设置colorbar
  2. window-运行perl脚本(搭建health-check环境)
  3. 【LeetCode】剑指 Offer 18. 删除链表的节点
  4. JAVA核心技术_【读】Java核心技术卷1
  5. 百度起诉今日头条;腾讯云超 8000 名员工获 iPhone 11 Pro 奖励;PHP 7.4.1 发布 | 极客头条...
  6. 【Linux】肝!Shell 脚本编程最佳实践
  7. 软件质量管理体系 type:pdf_普宁iso14001环境管理体系AAA信用等级认证
  8. java中文繁体简体转换
  9. 万字 常用设计软件大盘点|如何选择自己最适合的软件【建议收藏】
  10. 从 flask 服务端代码自动生成客户端代码 -- flask-native-stubs 库介绍
  11. 学籍管理html,河南学籍管理系统
  12. 彻底解决unable to find valid certification path to requested target
  13. 腾讯云永久修改主机名
  14. 【论文翻译 IJCAI-20】Heterogeneous Network Representation Learning 异构网络表示学习
  15. 双堆1.数据流的中位数
  16. Windows系统win10系统流程图软件推荐
  17. 大数据导论答案_2020高校邦《数据科学与大数据技术导论》课后作业答案
  18. php多线程原子操作,C语言线程互斥和原子操作
  19. flink的java api_Flink 流处理API之二
  20. 万历皇帝的金丝蟠龙翼善冠

热门文章

  1. 淘宝店铺如何装修呢?
  2. 求1000-2000年的闰年代码
  3. 第2章第6节:使用Slider滑杆在指定的范围内选择一个数值 [SwiftUI快速入门到实战]
  4. android自定义View之(四)------一键清除动画
  5. 水墨特效怎么做?两种方法快速搞定!大神都在用的超美视频画面效果
  6. PD快充DRP-TypeC连接状态机详解
  7. 微信灰度上线“群接龙”功能,据说只有1%的人能看到!
  8. nginx实现反向代理及负载均衡
  9. 大小写字母转换(java大小写字母转换)
  10. 阿里云短信服务Java实现