历史上的今天
今天是:2024年11月24日(星期日)
2021年11月24日 | DA转换(IIC总线)
2021-11-24 来源:eefocus
项目描述
向PCF8591芯片的AN2通道输入一个电压模拟量,经过AD转换后,单片机通过IIC总线读取转换后的数据,并将其量化后实时显示在LCD上。然后将AD转换后的数据写入PCF8591中进行DA转换,并用LED灯的亮度来显示模拟量的大小。
仿真原理图如下:

C语言代码如下:
/*------------------------
FileName: DAC.h
Function: 头文件
Author: Zhang Kaizhou
Date: 2019-6-13 17:12:49
------------------------*/
#include #include #include #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); /*DAC模块函数声明*/ void writeData8591(uchar dat); 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芯片的AN2通道输入一个电压模拟量, 经过AD转换后,单片机通过IIC总线读取转换后的数据, 并将其量化后实时显示在LCD上。 然后将AD转换后的数据写入PCF8591中进行DA转换, 并用LED灯的亮度来显示模拟量的大小。 Author: Zhang Kaizhou Date: 2019-6-13 17:12:40 ------------------------------------------------------*/ #include "DAC.h" void main(){ uchar dat = 0; initIIC(); LCDInit(); while(1){ /*AD转换*/ readData8591(2, &dat); // 读取通道2模拟输入量化后的数据 display(dat); delay(10); /*DA转换*/ writeData8591(dat); delay(10); } } /*向PCF85991写数据*/ void writeData8591(uchar dat){ /*向PCF8591写入地址字节和控制字节*/ startIIC(); writeDataIIC(0x90); // 向IIC总线发送寻址信号(PCF8591器件地址位90H),并声明要进行写操作 responseIIC(); writeDataIIC(0x40); // 向PCF8591写入控制字节(DA允许; AD为4路单端输入; 禁止自动增益) responseIIC(); /*向PCF8591中写入要进行DA转换的数据*/ startIIC(); responseIIC(); writeDataIIC(0x90); responseIIC(); writeDataIIC(dat); responseIIC(); stopIIC(); } /*从PCF8591的channel模拟输入所对应的ADC数据寄存器中读出数据到变量dat*/ void readData8591(uchar channel, uchar * dat){ /*向PCF8591写入地址字节和控制字节*/ startIIC(); writeDataIIC(0x90); // 向IIC总线发送寻址信号(PCF8591器件地址位90H),并声明要进行写操作 responseIIC(); writeDataIIC(0x40 | channel); // 向PCF8591写入控制字节(DA允许; AD为4路单端输入; 禁止自动增益; 选择通道channel) responseIIC(); /*从PCF8591读取数据*/ startIIC(); writeDataIIC(0x91); // 向IIC总线发送寻址信号,并声明要进行读操作 responseIIC(); readDataIIC(dat); stopIIC(); // 注意此处无响应信号,直接关闭IIC总线即可(否则会导致读取的数据不稳定) } /*---------------------------- FileName: IIC.c Function: 实现IIC总线基本操作 Author: Zhang Kaizhou Date: 2019-6-13 17:13:07 ----------------------------*/ #include "DAC.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 17:12:59 ------------------------------*/ #include "DAC.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--); }
下一篇:51单片机内部定时器的使用
史海拾趣
|
大家好,我是一个新人,前几天我们做的一个电子产品在做低温试验时,整个由单片机控制的部分都失效了,在室温放一段时间后又都正常了,我想问一问这大概是什么原因,是单片机或程序的问题吗,还是外围电路的问题。请大家发表意见,帮忙看一看!谢谢 ...… 查看全部问答> |
|
EVC的编译错误,主要是error LNK2019,高手请进,轻松拿分 ps2keybd.obj : error LNK2019: unresolved external symbol \"int __cdecl KernelIoControl(unsigned long,void *,unsigned long,void *,unsigned long,unsigned long *)\" (?KernelIoControl@@YAHKPAXK0KPAK@Z) referenced in function \"public: ...… 查看全部问答> |
|
WINCE里面,自己写的流接口驱动,怎么实现可以让应用程序向驱动里面注册一个回调函数?看到WINCE驱动里面有很多注册回调函数的驱动程序! WINCE里面,自己写的流接口驱动,怎么实现可以让应用程序向驱动里面注册一个回调函数?看到WINCE驱动里面有很多注册回调函数的驱动程序! 所以想实现这个机制,这样很方便的,也不用驱动给AP发消息了!!!… 查看全部问答> |
|
minicom启动后停在Uncompressing Linux......后不动了,为什么 虚拟机已经添加了串口设备,minicom的设置也已经设置好. 串口设置成/dev/ttyS0, BPS设置成:1152008N1. Hardware Flow Control:No. 启动minicom时出现以下这些字符,然后就停在那儿不动了,为什么? Uncompressing Linux.......................... ...… 查看全部问答> |
|
用3.7V的锂电池供电,要得到2.5V,2.8V,3.3V的输出需要用电源芯片吗? 在做个mp3,想用3.7V的锂电池供电,要得到2.5V,2.8V,3.3V的输出需要用电源芯片吗?串联电阻或是二极管降压可以吗?… 查看全部问答> |




