声明:本文为CSDN博主「田野麦子」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_38679924/article/details/91876414
项目描述
向PCF8591芯片的AN2通道输入一个电压模拟量,经过AD转换后,单片机通过IIC总线读取转换后的数据,并将其量化后实时显示在LCD上。然后将AD转换后的数据写入PCF8591中进行DA转换,并用LED灯的亮度来显示模拟量的大小。
仿真原理图如下
/*------------------------
FileName: ADC.h
Function: 头文件
Author: Zhang Kaizhou
Date: 2019-6-13 12:13:20
------------------------*/
#include <reg52.h>
#include <intrins.h>
#include <string.h>
#define uchar unsigned char
#define uint unsigned int
#define FACTOR 0.01953125 // 量化单位(用一个字节来量化表示5V的电压值,共为256个量化等级; FACTOR = 5 / 256)
/*IIC总线端口定义*/
sbit SDA = P2^0;
sbit SCL = P2^1;
/*LCD1602显示模块端口定义*/
sbit lcdrs = P1^0;
sbit lcdrw = P1^1;
sbit lcden = P1^2;
/*IIC总线模块函数声明*/
void initIIC();
void startIIC();
void responseIIC();
void stopIIC();
void writeDataIIC(uchar dat);
void readDataIIC(uchar * dat);
/*ADC模块函数声明*/
void readData8591(uchar channel, uchar * dat);
/*LCD1602显示模块函数声明*/
void writeCommand(uchar command);
void writeDataLCD(uchar dat);
void delay(uint xms);
void LCDInit();
void display(uchar dat);
/*-----------------------------------------
FileName: main.c
Function: ADC IIC
Description: 利用PCF8591芯片实现模数转换,
利用单片机通过IIC总线读取转换后的数据,
并将其量化后实时显示在LCD上。
Author: Zhang Kaizhou
Date: 2019-6-13 12:12:04
-----------------------------------------*/
#include "ADC.h"
void main(){
uchar dat = 0;
initIIC();
LCDInit();
while(1){
readData8591(2, &dat); // 读取通道2模拟输入量化后的数据
display(dat);
delay(10);
}
}
/*从PCF8591的channel模拟输入所对应的ADC数据寄存器中读出数据到变量dat*/
void readData8591(uchar channel, uchar * dat){
/*向PCF8591写入地址字节和控制字节*/
startIIC();
writeDataIIC(0x90); // 向IIC总线发送寻址信号(PCF8591器件地址位90H),并声明要进行写操作
responseIIC();
writeDataIIC(0x00 | channel); // 向PCF8591写入控制字节(DA禁止; AD为4路单端输入; 禁止自动增益; 选择通道channel)
responseIIC();
/*从PCF8591读出数据*/
startIIC();
writeDataIIC(0x91); // 向IIC总线发送寻址信号,并声明要进行读操作
responseIIC();
readDataIIC(dat);
stopIIC();
}
/*----------------------------
FileName: IIC.c
Function: 实现IIC总线基本操作
Author: Zhang Kaizhou
Date: 2019-6-13 12:15:49
----------------------------*/
#include "ADC.h"
/*IIC总线初始化*/
void initIIC(){
SCL = 1;
_nop_();
SDA = 1;
_nop_();
}
/*IIC总线启动信号*/
void startIIC(){ // 在SCL高电平期间,SDA产生一个下降沿表示启动
SDA = 1;
_nop_();
SCL = 1;
_nop_();
SDA = 0;
_nop_();
}
/*IIC总线应答信号*/
void responseIIC(){ // 从机在SCL高电平期间将SDA拉低表示应答
SDA = 0;
_nop_();
SCL = 1;
_nop_();
SCL = 0;
_nop_();
}
/*IIC总线停止信号*/
void stopIIC(){ // 在SCL高电平期间,SDA产生一个上升沿表示停止
SDA = 0;
_nop_();
SCL = 1;
_nop_();
SDA = 1;
_nop_();
}
/*向IIC总线写一个字节数据*/
void writeDataIIC(uchar dat){
uchar i, temp;
temp = dat;
for(i = 0; i < 8; i++){
temp = temp << 1;
SCL = 0;
_nop_();
SDA = CY;
_nop_();
SCL = 1;
_nop_();
}
SCL = 0;
_nop_();
SDA = 1;
_nop_();
}
/*从IIC总线读一个字节数据*/
void readDataIIC(uchar * dat){
uchar i;
SCL = 0;
_nop_();
SDA = 1;
_nop_();
for(i = 0; i < 8; i++){
SCL = 1;
_nop_();
* dat = ((* dat) << 1) | SDA;
SCL = 0;
_nop_();
}
}
/*-----------------------------
FileName:display.c
Function: LCD1602显示函数
Author: Zhang Kaizhou
Date: 2019-6-13 12:14:53
------------------------------*/
#include "ADC.h"
uchar code table0[] = {"ADC"};
uchar code table1[] = {"Voltage:"};
uchar code table2[] = {"0123456789"};
uchar num = 0;
/*初始化LCD1602的设置*/
void LCDInit(){
uchar i;
lcden = 0; // 拉低使能端,准备产生使能高脉冲信号
writeCommand(0x38); // 显示模式设置(16x2, 5x7点阵,8位数据接口)
writeCommand(0x0c); // 开显示,不显示光标
writeCommand(0x06); // 写一个字符后地址指针自动加1
writeCommand(0x01); // 显示清零,数据指针清零
/*LCD上电界面*/
writeCommand(0x80); // 将数据指针定位到第一行首
for(i = 0; i < strlen(table0); i++){
writeDataLCD(table0[i]);
delay(5);
}
writeCommand(0x80 + 0x40); // 将数据指针定位到第二行首
for(i = 0; i < strlen(table1); i++){
writeDataLCD(table1[i]);
delay(5);
}
}
/*LCD显示函数*/
void display(uchar dat){
/*数据的量化*/
float temp = FACTOR * dat;
uchar i, j;
if(dat == 255){
i = 5;
j = 0;
}else{ // 分离整数和小数部分
i = (uchar)temp;
j = (temp - i) * 10;
}
/*数据显示*/
writeCommand(0x80 + 0x40 + strlen(table1));
writeDataLCD(table2[i]);
delay(5);
writeCommand(0x80 + 0x40 + strlen(table1) + 1);
writeDataLCD('.');
delay(5);
writeCommand(0x80 + 0x40 + strlen(table1) + 2);
writeDataLCD(table2[j]);
delay(5);
}
/*写指令函数*/
void writeCommand(uchar command){
lcdrs = 0; // 命令选择
lcdrw = 0;
P0 = command;
delay(5);
lcden = 1; // 产生一个正脉冲使能信号
delay(5);
lcden = 0;
}
/*写数据函数*/
void writeDataLCD(uchar dat){
lcdrs = 1; // 数据选择
lcdrw = 0;
P0 = dat;
delay(5);
lcden = 1;
delay(5);
lcden = 0;
}
/*延时xms函数*/
void delay(uint xms){
uint i, j;
for(i = xms; i > 0; i--)
for(j = 110; j > 0; j--);
}