利用A/D,加上简单的计算,加上串口打印,我们就可以简单的测量电压了。就可以做简单的电压或电流表了。调节电位器,电压会变化,led灯也会变化,电脑显示实验现象如图:
源代码:
- 项目名称:PCF8591AD和串口打印
- 项目内容:A/D转换,把转换的数字量
- 送给P0口控制LED的亮灭 ;
- 并把转换的数字逻辑
- 运算,送给串口,打印到电脑上。
- 这样就可以采样电压信号了,并处理。
- 可以扩展做出电压表,电流表等。
- 作者:YUAN
- */
- #include <reg52.h>
- #include <stdio.h> //printf输出头文件
- #include <intrins.h> //_nop_()延时头文件
- typedef unsigned char uChar8;
- typedef unsigned int uInt16;
- sbit SDA = P1^0;
- sbit SCL = P1^1;
- #define PCF8591Add 0x90 //PCF8591的器件地址和写操作
- uChar8 gTemp;
- float gfDataVal; //用在转载计算的数值,并发送给计算机
- //延时函数
- void DelayMS(uInt16 lValMS);
- void Delay5us(void);
- //IIC操作的几个函数
- void IICInit(void); //IIC初始化
- void IICStart(void); //起始信号
- void IICStop(void); //停止信号
- void IICAck(void); //应答信号
- void IICReadAck(void); //读应答信号
- void IICWriteOneByte(uChar8 lByteVal); //写一个字节
- uChar8 IICReadOneByte(void); //读一个字节
- void PCF8591WriteRegulate(uChar8 lREGVal); //Regulate控制器,这里写控制函数
- uChar8 ReadDataPCF8591(void);
- //
- //串口的几个程序
- void UartInit(void); //串口初始化
- void UartPrint(float iVal); //Printd打印,打印函数
- void main()
- {
- IICInit();
- UartInit();
- while(1)
- {
- /*写入控制字00,即模拟量输出关闭,选择通道0,
- 不自动增加通道,模拟量输入围方式0*/
- PCF8591WriteRegulate(0x00);
- P0 = ReadDataPCF8591();
- gTemp = P0; //用来中转的存储区
- gfDataVal = (float)gTemp/255*5; //强制转换
- DelayMS(1000);
- UartPrint(gfDataVal);
- }
- }
- void DelayMS(uInt16 lValMS) //延时函数
- {
- uInt16 luiVal,lujVal;
- for(luiVal = 0; luiVal < lValMS; luiVal++)
- for(lujVal = 0; lujVal < 113; lujVal++);
- }
- void Delay5us(void)
- {
- _nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();
- }
- //IIC总线空闲时均为高电平
- void IICInit(void) //IIC初始化
- {
- SCL = 0;
- SDA=1;
- Delay5us();
- SCL=1;
- }
- //SCL高电平期间SDA由高到低的变化为起始信号
- void IICStart(void) //起始信号
- {
- SCL = 0;
- Delay5us();
- SDA = 1;
- Delay5us();
- SCL = 1;
- Delay5us();
- SDA = 0;
- Delay5us();
- //防止接下来SDA数据变化导致IIC总线误判
- SCL = 0;
- }
- //SCL高电平期间SDA由低到高的变化为终止信号
- void IICStop(void) //停止信号
- {
- SCL = 0;
- Delay5us();
- SDA = 0;
- Delay5us();
- SCL = 1;
- Delay5us();
- SDA = 1;
- Delay5us();
- //防止接下来SDA数据变化导致IIC总线误判
- SCL = 0;
- }
- //一个脉冲期间,SDA为低电平为应答
- void IICAck(void) //应答信号
- {
- SCL = 0;
- Delay5us();
- SDA = 0;
- Delay5us();
- SCL = 1;
- Delay5us();
- SCL = 0;
- }
- /*cpu读应答信号,如果应答了则
- 继续传输数据,否则在一定时间里,
- 默认已经应答,继续传数据
- */
- void IICReadAck(void) //读应答信号
- {
- uChar8 li = 0;
- SCL = 0;
- SDA = 1; //确保读出的值为0,因此先送1
- Delay5us();
- SCL = 1;
- Delay5us();
- //如果没有应答或时间没有超过预定时间则停在此处
- while((1 == SDA)&&(li<255))li++;
- SCL = 0;
- Delay5us();
- SDA = 1;
- }
- /*
- 写1个字节,先写高位。
- */
- void IICWriteOneByte(uChar8 lByteVal) //写一个字节
- {
- uChar8 li,liVal;
- liVal = lByteVal;
- for(li=0;li<8;li++)
- {
- SCL = 0;
- Delay5us();
- SDA = (bit)(liVal&0x80); //把数据准备好等待传送
- Delay5us();
- SCL = 1;
- Delay5us();
- liVal <<= 1;
- }
- SCL = 0;
- Delay5us();
- SDA = 1;
- }
- /*
- 读取一个字节并把读到的值返回
- */
- uChar8 IICReadOneByte(void)
- {
- uChar8 li,liVal;
- SCL = 0;
- SDA = 1;
- for(li=0;li<8;li++)
- {
- liVal <<= 1;
- SCL = 0;
- Delay5us();
- SCL = 1;
- Delay5us();
- liVal = (liVal|SDA);
- }
- SCL = 0;
- return liVal;
- }
- //Regulate控制器,这里写控制函数
- void PCF8591WriteRegulate(uChar8 lREGVal)
- {
- IICStart();
- IICWriteOneByte(PCF8591Add); //PCF8591的地址,写控制
- IICReadAck();
- IICWriteOneByte(lREGVal); //写入控制字
- IICReadAck();
- IICStop();
- }
- uChar8 ReadDataPCF8591(void)
- {
- uChar8 liVal;
- IICStart();
- IICWriteOneByte(PCF8591Add|0x01); //PCF8591的地址,读控制
- liVal = IICReadOneByte();
- IICAck();
- IICStop();
- return liVal;
- }
- //串口的程序
- void UartInit(void)
- {
- TMOD &= 0x0f; //只改变要改变的
- TMOD |= 0x20; //设置定时器0为工作方式2
- TL1 = 0xfd;
- TH1 = 0xfd; //设置波特率为9600bps
- TR1 = 1; //允许T1开始计数
- SCON &= 0x5f;
- SCON |= 0x50; //设置串口工作在方式1,允许接收数据
- }
- //把读出来的值打印到计算机上
- void UartPrint(float iVal)
- {
- TI=1;
- printf("测得电压为:%f\n",iVal);
- while(!TI);
- TI=0;
- }