附件里面有设计任务,根据附件原理图改正里面的程序。完整的word文档请在本文最后下载附件,下面是部分内容预览:
目 录 一、原理 ……………………………………………………………………………………………1 二、硬件介绍 ………………………………………………………………………………………1 2.1 单片机介绍…………………………………………………………………………………1 2.2 AT24C02I2C数据存储 ……………………………………………………………………2 2.3 PCF8591 A/D转换 …………………………………………………………………………2 2.4 LCD1602 液晶显示模块……………………………………………………………………3 硬件连接及工作过程简介………………………………………………………………………4 3.1 硬件连接……………………………………………………………………………………4 3.2 工作过程简介………………………………………………………………………………5 三、工作流程图 ……………………………………………………………………………………6 四、程序清单 ………………………………………………………………………………………7 五、PCB图 …………………………………………………………………………………………18 六、总结……………………………………………………………………………………………18 八、参考文献………………………………………………………………………………………19
一、原理本文所设计的是一种以单片机STC12C5A60S2(引脚排序及基本功能同AT89S51)作为主控芯片的双通道电压采集电路,将采集到的模拟信号电压值利用PCF8591来进行模数转换,PCF8591是一个单片集成、单独供电、低功耗、8-bitCMOS数据获取信号。其中PCF8591共有4个模拟输入、一个模拟输出和一个串行口I2C总线接口,通过PLCF8591将转换成的数字信号电压值传给液晶显示屏,并将所测电压值在LCD1602液晶显示屏中显示出来,而且要利用AT24C04设置电压上下限,在电压超出上下限时显示屏要有所表示.本文主要针对双通道的数据采集与显示,继而推广多通道数据采集的方法,重点分析介绍了基于AT89S51数字电压采集的硬件设计和软件设计。
图3-1硬件连接原理图
SDA、SCL是IIC数据线和时钟线,可连接于单片机任何IO管脚在。在本次设计中通过芯片AT24C02来编写所测电压的上下限值。 我们这次试验所测得电压是直流电压0至5伏是模拟信号由于我们所测得电压要在 LCD1602 液晶显示屏中显示出来,但是LCD1602液晶显示屏接受和表达数字信号,所以要用PCF8591 A/D转换芯片把采集的模拟信号电压值转换成数值信号,经过AT89S51再把信号传给LCD液晶显示屏,最终在液晶显示屏上显示出电压值。如果采集的电压值在设定的电压值之间,则电压值能在液晶显示屏上显示出电压,如果超出了则在液晶显示屏上有所表示。在此次试验中因为是双通道采集电压,所以我们测两条电路的电压,我在这两条电路上各串联了一个滑动变阻器,用来改变所测的电压值。
五、程序清单 - #include "common.h"
- float v_low = 2.8; //电压范围下限
- float v_high = 4.5; //电压范围上限
- uchar BUF[2]; //从at24c04中读取的数据存储在这
- uchar w_buf[2]; //写入at24c04中的数据存在这里
- //延时函数大约1ms
- void delay_ms(int ms)
- {
- int i;
- while(ms--)
- {
- for(i=0;i<100;i++);
- }
- }
- //连续写入两个数据
- void AT24C04_Write(uchar dat_1,uchar dat_2)
- {
- AT24C04_Start(); //起始信号
- AT24C04_SendByte(0xa0); //发送设备地址+写信号
- AT24C04_SendByte(0x00); //发送存储单元地址
- AT24C04_SendByte(dat_1); //写入数据1
- AT24C04_SendByte(dat_2); //写入数据2
- AT24C04_Stop(); //停止信号
- }
- //连续读出两个数据
- void AT24C04_ReadPage()
- {
- uchar i;
- AT24C04_Start(); //起始信号
- AT24C04_SendByte(0xa0); //发送设备地址+写信号
- AT24C04_SendByte(0x00); //发送存储单元地址
- AT24C04_Start(); //起始信号
- AT24C04_SendByte(0xa1); //发送设备地址+读信号
- for (i=0; i<2; i++)
- {
- BUF[i] = AT24C04_RecvByte();
- if (i == 1)
- {
- AT24C04_SendACK(1); //最后一个数据需要会NAK
- }
- else
- {
- AT24C04_SendACK(0); //回应ACK
- }
- }
- AT24C04_Stop(); //停止信号
- }
- //LCD显示数字处理函数
- void show_num(uchar num,uchar flag)
- {
- uchar temp[3],i;
- float re_val; //电压实际值
- float read_low,read_h; //将从AT24C04中读取电压范围数据转化成对应小数形式
- re_val = num/255.0*5.0; //实际电压计算公式
- num = re_val*10; //保留一位小数
- AT24C04_ReadPage();//从AT24C04中读取电压范围数据,存储在BUF数组中
- // BUF[0]表示下限,BUF[1]表示上限
- //存入AT24C04中的数据是uchar unsigned型,在这里转化成float型
- read_low = BUF[0]/10.0;
- read_h = BUF[1]/10.0;
- if(re_val >= read_low && re_val <= read_h) //如果电压在范围内
- {
- temp[0] = num/10 + '0';
- temp[1] = '.';
- temp[2] = num%10 + '0';
- }else if(re_val < read_low ) //如果低于设定值
- {
- temp[0] = 'L';
- temp[1] = 'O';
- temp[2] = 'W';
- }else if(re_val > read_h ) //如果高于设定值
- {
- temp[0] = 'H';
- temp[1] = 'I';
- temp[2] = 'G';
- }
-
- for(i=0;i<3;i++) //用液晶显示结果
- {
- LCD_Manifest(flag,3+i,temp[i]);
- }
- //显示电压范围的上限
- num = read_h * 10;
- temp[0] = num/10 + '0';
- temp[1] = '.';
- temp[2] = num%10 + '0';
- for(i=0;i<3;i++) //用液晶显示结果
- {
- LCD_Manifest(1,12+i,temp[i]);
- }
- //显示电压范围的下限
- num = read_low * 10;
- temp[0] = num/10 + '0';
- temp[1] = '.';
- temp[2] = num%10 + '0';
- for(i=0;i<3;i++) //用液晶显示结果
- {
- LCD_Manifest(2,12+i,temp[i]);
- }
- }
- //主函数
- void main()
- {
- uchar val; //电压值
- LCD_Init(); //液晶初始化
- IIC_Init(); //I2C总线初始化
- w_buf[0] = v_low*10;
- w_buf[1] = v_high*10;
- AT24C04_Write(w_buf[0],w_buf[1]); //将数据写入AT24C04
-
- LCD_Manifest(1,0,'V'); //在lcd1602中显示字符
- LCD_Manifest(1,1,'1');
- LCD_Manifest(1,2,':');
- LCD_Manifest(2,0,'V');
- LCD_Manifest(2,1,'2');
- LCD_Manifest(2,2,':');
- LCD_Manifest(1,10,'H');
- LCD_Manifest(1,11,':');
- LCD_Manifest(2,10,'L');
- LCD_Manifest(2,11,':');
- while(1)
- {
- //按键检测程序
- if(key_1 == 0) //调节范围的下限
- {
- delay_ms(100); //延时消除抖动
- if(key_1 == 0)
- {
- // v_low = v_low - 0.1;
- // if(v_low < 0.0)
- // v_low = v_high;
- w_buf[0] = v_low*10;
- w_buf[1] = v_high*10;
- AT24C04_Write(w_buf[0],w_buf[1]); //将数据写入AT24C04
- }
- }
- if(key_2 == 0) //调节范围的上限
- {
- delay_ms(100); //延时消除抖动
- if(key_2 == 0)
- {
- v_high = v_high + 0.1;
- if(v_high > 5.0)
- v_high = v_low;
- w_buf[0] = v_low*10;
- w_buf[1] = v_high*10;
- AT24C04_Write(w_buf[0],w_buf[1]); //将数据写入AT24C04
- }
- }
- ADC_Send_Byte(0x90,0x41);//通道一ADC转换
- val=ADC_Receive_Byte(0x90); //读取AD转换的值
- show_num(val,1);
- ADC_Send_Byte(0x90,0x42);//通道二ADC转换
- val=ADC_Receive_Byte(0x90); //读取AD转换的值
- show_num(val,2);
- }
- }
- #include<iic.h>
- void IIC_Init()//总线初始化
- {
-
- SCL=1;
- IIC_DELAY();
- SDA=1;
- IIC_DELAY();
- }
- void IIC_Start() //启动信号
- {
-
- SDA=1;
- IIC_DELAY();
- SCL=1;
- IIC_DELAY();
- SDA=0;
- IIC_DELAY();
- }
- void IIC_Stop() //停止信号
- {
-
- SDA=0;
- IIC_DELAY();
- SCL=1;
- IIC_DELAY();
- SDA=1;
- IIC_DELAY();
- }
- void IIC_Ack() //应答信号
- {
- unsigned char i;
- SCL=1;
- IIC_DELAY();;
- while((SDA==1)&&(i<255))i++;
- SCL=0;
- IIC_DELAY();
- }
- void IIC_Write_Byte(u8 date)//写一个字节
- {
- u8 i,temp;
- temp=date;
- for(i=0;i<8;i++)
- {
- temp=temp<<1;
- SCL=0;
- IIC_DELAY();
- SDA=CY;//最高位将移入PSW寄存器的CY位中,然后将CY赋给SDA
- IIC_DELAY();
- SCL=1;
- IIC_DELAY();
- }
- SCL=0;
- IIC_DELAY();
- SDA=1;
- IIC_DELAY();
- }
- u8 IIC_Read_Byte()//读一个字节
- {
- u8 i,temp;
- for(i=0;i<8;i++)
- {
- SCL=0;
- IIC_DELAY();
- temp=(temp<<1)|SDA;
- IIC_DELAY();
- SCL=1;
- IIC_DELAY();
- }
- SCL=0;
- IIC_DELAY();
- SDA=1;
- IIC_DELAY();
- return temp;
- }
- #include <reg51.h>
- #include"lcd1602.h"
- void delay(u8 z)//延时函数
- {
- unsigned char x,y;
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
- }
- void LCD_Write_Cmd(u8 com )//液晶写命令
- {
- LCD_RS=0;//选择写命令模式
- LCD_dat=com;//将要写的命令字送到数据总线上
- delay(1);
- LCD_E=1;//使能端给一高脉冲,高脉冲有效
- delay(1);
- LCD_E=0;
- }
- void LCD_Write_Data(u8 date)//数据写命令
- {
- LCD_RS=1;//选择写数据模式
- LCD_dat=date;
- delay(1);
- LCD_E=1;//使能端给一高脉冲,高脉冲有效
- delay(1);
- LCD_E=0;
- }
- void LCD_Init()//液晶初始化
- {
-
- LCD_WR=0;
- LCD_Write_Cmd(0x38);//设置16*2显示,5*7点阵,8位数据接口
- LCD_Write_Cmd(0x0c);//设置开显示,不显示光标
- LCD_Write_Cmd(0x06);//写一个字符后地址指针自动加1
- LCD_Write_Cmd(0x80);//数据指针定位到第一行第一个字处
- }
- // 使得写命令和写数据通过一个函数完成
- void LCD_Manifest(u8 row,u8 add,u8 date)
- {
- if(row==1) LCD_Write_Cmd(0x80+add);
- if(row==2) LCD_Write_Cmd(0xc0+add);
- LCD_Write_Data(date);
- }
- #include"iic.h"
- #include"pcf8591.h"
- //ADC发送字节[命令]数据函数
- void ADC_Send_Byte(u8 addr,u8 com)
- {
- IIC_Start(); //启动总线
- IIC_Write_Byte(addr); //发送器件地址
- IIC_Ack();
- IIC_Write_Byte(com); //发送数据
- IIC_Ack();
- IIC_Stop(); //结束总线
- }
- //ADC读字节数据函数
- u8 ADC_Receive_Byte(u8 addr)
- {
- u8 c;
- IIC_Start(); //启动总线
- IIC_Write_Byte(addr+1); //发送器件地址,如果是读则最低位为1即0x91
- IIC_Ack();
- c=IIC_Read_Byte(); //读取数据
- IIC_Ack(); //发送非就答位
- IIC_Stop(); //结束总线
- return(c);
- }
- #include"AT24C04.h"
- void Delay5us()
- {
- BYTE n = 4;
- while (n--)
- {
- _nop_();
- _nop_();
- }
- }
- void Delay5ms()
- {
- WORD n = 2500;
- while (n--)
- {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }
- }
- void AT24C04_Start()
- {
- AT_SDA = 1; //拉高数据线
- AT_SCL = 1; //拉高时钟线
- Delay5us(); //延时
- AT_SDA = 0; //产生下降沿
- Delay5us(); //延时
- AT_SCL = 0; //拉低时钟线
- }
- void AT24C04_Stop()
- {
- AT_SDA = 0; //拉低数据线
- AT_SCL = 1; //拉高时钟线
- Delay5us(); //延时
- AT_SDA = 1; //产生上升沿
- Delay5us(); //延时
- }
- void AT24C04_SendACK(bit ack)
- {
- AT_SDA = ack; //写应答信号
- AT_SCL = 1; //拉高时钟线
- Delay5us(); //延时
- AT_SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- bit AT24C04_RecvACK()
- {
- AT_SCL = 1; //拉高时钟线
- Delay5us(); //延时
- CY = AT_SDA; //读应答信号
- AT_SCL = 0; //拉低时钟线
- Delay5us(); //延时
- return CY;
- }
- void AT24C04_SendByte(BYTE dat)
- {
- BYTE i;
- for (i=0; i<8; i++) //8位计数器
- {
- dat <<= 1; //移出数据的最高位
- AT_SDA = CY; //送数据口
- AT_SCL = 1; //拉高时钟线
- Delay5us(); //延时
- AT_SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- AT24C04_RecvACK();
- }
- BYTE AT24C04_RecvByte()
- {
- BYTE i;
- BYTE dat = 0;
- AT_SDA = 1; //使能内部上拉,准备读取数据
- for (i=0; i<8; i++) //8位计数器
- {
- dat <<= 1;
- AT_SCL = 1; //拉高时钟线
- Delay5us(); //延时
- dat |= AT_SDA; //读数据
- AT_SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- return dat;
- }
复制代码
七、总结 本次课程设计,我学到了很多的东西,对汇编语言程序设计加深了理解和掌握,我们这次设计的要求主要是熟悉微型计算机技术中所学到的几中芯片的使用,掌握它们的初始化编程,并学会他们的基本应用,这是一个比较全面的设计,和以前的实验相比较复杂很多,一方面要求我们设计硬件电路,另一方面需要对设计的硬件电路进行编程,这就需要软件和硬件相结合,具体的电路具体分析,在此次设计中还用到了AT24C02芯片,在此次之前我们从没用到这个芯片,对这个芯片非常陌生,而且网上也没有什么系统的解释,和AT89S51的管脚的连线也不清楚,但是最后通过不停地调试,最后还是被解决了。通过这次课程设计后,我对学硬件有了一定的体会,它要求我们认真仔细的做好每个环节,对所有的问题要考虑周全,它和软件不同,对具体的电路要编写适合该电路的程序,电路一改,程序也要跟着改,从中我也学会了很多实际应用的知识。通过本次设计,我才发现我所学的东西的肤浅,知识面的不牢固,在选择方案的时候,产生模棱两可的情况。经常是边设计边复习学习过的课本知识。这些使我知道“纸上谈兵”是绝对不行,只有通过实践,自己亲自动手试一试,才能发现自己知识的缺陷,才能更好的与所学的知识相结合。在课程设计中我们每个人都能学到很多,有很大的收获。做任何事情所要有的态度和心态,首先我明白了做学问要一丝不苟,对于出现的任何问题和偏差都不要轻视,要通过正确的途径去解决,在做事情的过程中要有耐心和毅力,不要一遇到困难就打退堂鼓,只要坚持下去就可以找到思路去解决问题的。在工作中要学会与人合作的态度,认真听取别人的意见,这样做起事情来就可以事倍功半。
课程设计任务书下载:
任务书10----双通道电压采集电路设计(LCD显示).doc
(36.5 KB, 下载次数: 19)
完整的设计文档下载:
单片机课设.doc
(214.5 KB, 下载次数: 49)
|