很高兴来到这里。
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
元件清单:
单片机STC89C52 1片
单片机座 1个
晶振11.0592M 1个
独石电容30pF 2个
电解电容10uF 1个
电解电容220uF 1个
电阻10K 1个
排阻10K(103) 1片
按键 2个
1602液晶 1个
1602液晶座 1个
电位器10K(103) 1个
PM2.5传感器 GP2Y1051AU0F 1个
有源蜂鸣器 1个
S8550(PNP)三极管 1个
洞洞板9*15cm 1张
电源座 1个
电源开关 1个
电源线 1根
为什么会有两个原理图呢?
1、两个原理图本质是一样的,只不过连接方式不同而已。
2、原理图1是以模块化的形式展现,模块和模块之间通过网络编号
关联起来,这样连接的好处是整个原理图看起来非常简洁明了。
3、原理图2中,各个元件都通过导线连接起来,好处是看起来比较
直观,缺点是整个图给人的感觉比较乱。
4、建议,最好是采用原理图1的连接方式,这种修改和查看都
都比较方便的。之所以还给了一个原理图2,是满足部分有强迫
症的同学,他们没看到有导线相连,总觉得不对。其实原理图1
这种网络编号连接才是规范的。
以后出去工作接触的项目,要么一个芯片上百个引脚,要么一个
原理图上百个元件,要是都通过线来连接,可以想象整个原理图
将是多么的乱,已经失去了原理图的意义了,所以还是建议采用
模块化的思想来画原理图。
一、程序用什么软件查看?
打开程序的软件是Keil,我们提供了相关的安装包,放在资料包
《24、软件--Keil 安装包》里面。
二、如何复制到word?
1、进入“程序(Keil版)”这个文件夹;
2、找到“main.c”这个文件,程序源码就在这个文件里面;
3、用电脑自带的记事本软件可以打开这个“main.c”文件;
4、用记事本打开之后,自己复制到word就可以了;
三、如何下载程序到板子上?
我们提供了下载程序的视频教程,放在资料包《19、如何下载
单片机程序》。
单片机源程序如下:
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char // 以后unsigned char就可以用uchar代替
- #define uint unsigned int // 以后unsigned int 就可以用uint 代替
- sfr ISP_DATA = 0xe2; // 数据寄存器
- sfr ISP_ADDRH = 0xe3; // 地址寄存器高八位
- sfr ISP_ADDRL = 0xe4; // 地址寄存器低八位
- sfr ISP_CMD = 0xe5; // 命令寄存器
- sfr ISP_TRIG = 0xe6; // 命令触发寄存器
- sfr ISP_CONTR = 0xe7; // 命令寄存器
- sbit LcdRs_P = P2^7; // 1602液晶的RS管脚
- sbit LcdRw_P = P2^6; // 1602液晶的RW管脚
- sbit LcdEn_P = P2^5; // 1602液晶的EN管脚
- sbit Key1_P = P3^2; // 减按键
- sbit Key2_P = P3^3; // 加按键
- sbit Buzzer_P = P1^0; // 蜂鸣器
- uint gAlarm ; // 报警值
- uchar gIndex=0; // 串口接收索引
- uint Value[20]={0}; // 串口数据缓存区
- /*********************************************************/
- // 单片机内部EEPROM不使能
- /*********************************************************/
- void ISP_Disable()
- {
- ISP_CONTR = 0;
- ISP_ADDRH = 0;
- ISP_ADDRL = 0;
- }
- /*********************************************************/
- // 从单片机内部EEPROM读一个字节,从0x2000地址开始
- /*********************************************************/
- unsigned char EEPROM_Read(unsigned int add)
- {
- ISP_DATA = 0x00;
- ISP_CONTR = 0x83;
- ISP_CMD = 0x01;
- ISP_ADDRH = (unsigned char)(add>>8);
- ISP_ADDRL = (unsigned char)(add&0xff);
- // 对STC89C51系列来说,每次要写入0x46,再写入0xB9,ISP/IAP才会生效
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- ISP_Disable();
- return (ISP_DATA);
- }
- /*********************************************************/
- // 往单片机内部EEPROM写一个字节,从0x2000地址开始
- /*********************************************************/
- void EEPROM_Write(unsigned int add,unsigned char ch)
- {
- ISP_CONTR = 0x83;
- ISP_CMD = 0x02;
- ISP_ADDRH = (unsigned char)(add>>8);
- ISP_ADDRL = (unsigned char)(add&0xff);
- ISP_DATA = ch;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- ISP_Disable();
- }
- /*********************************************************/
- // 擦除单片机内部EEPROM的一个扇区
- // 写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除
- /*********************************************************/
- void Sector_Erase(unsigned int add)
- {
- ISP_CONTR = 0x83;
- ISP_CMD = 0x03;
- ISP_ADDRH = (unsigned char)(add>>8);
- ISP_ADDRL = (unsigned char)(add&0xff);
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- ISP_Disable();
- }
- /*********************************************************/
- // 毫秒级的延时函数,time是要延时的毫秒数
- /*********************************************************/
- void DelayMs(uint time)
- {
- uint i,j;
- for(i=0;i<time;i++)
- for(j=0;j<112;j++);
- }
- /*********************************************************/
- // 1602液晶写命令函数,cmd就是要写入的命令
- /*********************************************************/
- void LcdWriteCmd(uchar cmd)
- {
- LcdRs_P = 0;
- LcdRw_P = 0;
- LcdEn_P = 0;
- P0=cmd;
- DelayMs(2);
- LcdEn_P = 1;
- DelayMs(2);
- LcdEn_P = 0;
- }
- /*********************************************************/
- // 1602液晶写数据函数,dat就是要写入的数据
- /*********************************************************/
- void LcdWriteData(uchar dat)
- {
- LcdRs_P = 1;
- LcdRw_P = 0;
- LcdEn_P = 0;
- P0=dat;
- DelayMs(2);
- LcdEn_P = 1;
- DelayMs(2);
- LcdEn_P = 0;
- }
- /*********************************************************/
- // 1602液晶初始化函数
- /*********************************************************/
- void LcdInit()
- {
- LcdWriteCmd(0x38); // 16*2显示,5*7点阵,8位数据口
- LcdWriteCmd(0x0C); // 开显示,不显示光标
- LcdWriteCmd(0x06); // 地址加1,当写入数据后光标右移
- LcdWriteCmd(0x01); // 清屏
- }
- /*********************************************************/
- // 液晶光标定位函数
- /*********************************************************/
- void LcdGotoXY(uchar line,uchar column)
- {
- // 第一行
- if(line==0)
- LcdWriteCmd(0x80+column);
- // 第二行
- if(line==1)
- LcdWriteCmd(0x80+0x40+column);
- }
- /*********************************************************/
- // 液晶输出数字
- /*********************************************************/
- void LcdPrintNum(uint num)
- {
- if(num>999)
- {
- LcdWriteData(num/1000+48); // 如果有千位,则输出千位
- }
- else // 如果没有千位,则输出空格
- {
- LcdWriteData(' ');
- }
- LcdWriteData(num%1000/100+48); // 百位
- LcdWriteData(num%100/10+48); // 十位
- LcdWriteData(num%10+48); // 个位
- }
- /*********************************************************/
- // 液晶输出字符串函数
- /*********************************************************/
- void LcdPrintStr(uchar *str)
- {
- while(*str!='\0')
- LcdWriteData(*str++);
- }
- /*********************************************************/
- // 液晶显示内容初始化
- /*********************************************************/
- void LcdShowInit()
- {
- LcdGotoXY(0,0); // 液晶光标定位到第0行第0列
- LcdPrintStr("PM2.5: ug/m3");
- LcdGotoXY(1,0); // 液晶光标定位到第1行第0列
- LcdPrintStr("Alarm: ug/m3");
- }
- /*********************************************************/
- // 串口初始化
- /*********************************************************/
- void UartInit()
- {
- TMOD = 0x20;
- SCON = 0x50;
- TH1 = 0xf4;
- TL1 = 0xf4;
- TR1 = 1;
- REN = 1;
- EA = 1;
- ES = 1;
- }
- /*********************************************************/
- // 按键扫描
- /*********************************************************/
- void KeyScanf()
- {
- /* 减按键被按下 */
- if(Key1_P==0)
- {
- if(gAlarm>1) // 只有报警值大于1,才能完成减操作
- {
- gAlarm--; // 报警值减1
- LcdGotoXY(1,6); // 液晶定位到第1行第6列
- LcdPrintNum(gAlarm); // 显示报警浓度值
- Sector_Erase(0x2000); // 存储之前必须先擦除
- EEPROM_Write(0x2000,gAlarm/100); // 存储新的报警值
- EEPROM_Write(0x2001,gAlarm%100);
- }
- }
-
- /* 减按键被按下 */
- if(Key2_P==0)
- {
- if(gAlarm<1300) // 只有报警值小于1300,才能完成加操作
- {
- gAlarm++; // 报警值加1
- LcdGotoXY(1,6); // 液晶定位到第1行第6列
- LcdPrintNum(gAlarm); // 显示报警浓度值
- Sector_Erase(0x2000); // 存储之前必须先擦除
- EEPROM_Write(0x2000,gAlarm/100); // 存储新的报警值
- EEPROM_Write(0x2001,gAlarm%100);
- }
- }
- }
- /*********************************************************/
- // 报警判断
- /*********************************************************/
- void AlarmJudge(uint num)
- {
- if(num>gAlarm)
- Buzzer_P=0; // 开启蜂鸣器报警
- else
- Buzzer_P=1; // 停止蜂鸣器报警
- }
- /*********************************************************/
- // 主函数
- /*********************************************************/
- void main(void)
- {
- uchar i; // 循环变量
- uint ret; // 保存测量结果
-
- gAlarm=EEPROM_Read(0x2000)*100+EEPROM_Read(0x2001); // 上电时,先读取报警值
- if((gAlarm==0)||(gAlarm>999)) // 如果读取到的报警值异常,则重新赋值
- gAlarm=200;
-
-
- LcdInit(); // 液晶功能初始化
- LcdShowInit(); // 液晶显示初始化
- UartInit(); // 串口初始化
- LcdGotoXY(1,6); // 液晶定位到第1行第6列
- LcdPrintNum(gAlarm); // 显示报警浓度值
-
- while(1)
- {
- ret=0; // 清零测量结果
- for(i=0;i<20;i++) // 将最新的20个测量结果求和
- {
- ret=ret+Value[i];
- }
- ret=ret/20; // 再除以20求得平均值
-
- ret=((ret*5)/1024.0)*380; // 将读取到的电压值转换为灰尘浓度值
-
- LcdGotoXY(0,6); // 液晶定位到第0行第6列
- LcdPrintNum(ret); // 显示测量结果
-
- AlarmJudge(ret); // 判断是否需要报警
-
- KeyScanf(); // 进行按键扫描,判断是否有按键按下
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
全部资料51hei下载地址:
10、元件清单.rar
(2.97 KB, 下载次数: 82)
07、单片机程序.rar
(39.13 KB, 下载次数: 117)
08、电路图(原理图和PCB图).rar
(514.6 KB, 下载次数: 129)
|