您现在的位置: 主页 > MCU > 单片机应用 > PCF8591 应用程序 -
本文所属标签:
为本文创立个标签吧:

PCF8591 应用程序 -

来源: 网络用户发布,如有版权联系网管删除 2018-09-08 

[导读]PCF8591 的通信接口是 I2C,那么编程肯定是要符合这个协议的。单片机对 PCF8591 进行初始化,一共发送三个字节即可。第一个字节,和 EEPROM 类似,是器件地址字节,其中7位代表地址,1位代表读写方向。地址高4位固定

PCF8591 的通信接口是 I2C,那么编程肯定是要符合这个协议的。单片机对 PCF8591 进行初始化,一共发送三个字节即可。第一个字节,和 EEPROM 类似,是器件地址字节,其中7位代表地址,1位代表读写方向。地址高4位固定是 0b1001,低三位是 A2,A1,A0,这三位我们电路上都接了 GND,因此也就是 0b000,如图17-5所示。

本文引用地址: http://www.21ic.com/app/mcu/201807/778653.htm

图17-5 PCF8591 地址字节

发送到 PCF8591 的第二个字节将被存储在控制寄存器,用于控制 PCF8591 的功能。其中第3位和第7位是固定的0,另外6位各自有各自的作用,如图17-6所示,我逐一介绍。

图17-6 PCF8591 控制字节

控制字节的第6位是 DA 使能位,这一位置1表示 DA 输出引脚使能,会产生模拟电压输出功能。第4位和第5位可以实现把 PCF8591 的4路模拟输入配置成单端模式和差分模式,单端模式和差分模式的区别,我们在17.5节有介绍,这里大家只需要知道这两位是配置 AD 输入方式的控制位即可,如图17-7所示。

图17-7 PCF8591 模拟输入配置方式

控制字节的第2位是自动增量控制位,自动增量的意思就是,比如我们一共有4个通道,当我们全部使用的时候,读完了通道0,下一次再读,会自动进入通道1进行读取,不需要我们指定下一个通道,由于 A/D 每次读到的数据,都是上一次的转换结果,所以同学们在使用自动增量功能的时候,要特别注意,当前读到的是上一个通道的值。为了保持程序的通用性,我们的代码没有使用这个功能,直接做了一个通用的程序。

控制字节的第0位和第1位就是通道选择位了,00、01、10、11代表了从0到3的一共4个通道选择。

发送给 PCF8591 的第三个字节 D/A 数据寄存器,表示 D/A 模拟输出的电压值。D/A 模拟我们一会介绍,大家知道这个字节的作用即可。我们如果仅仅使用 A/D 功能的话,就可以不发送第三个字节。

下面我们用一个程序,把 AIN0、AIN1、AIN3 测到的电压值显示在液晶上,同时大家可以转动电位器,会发现 AIN0 的值发生变化。 /*Lcd1602.c 文件程序源代码***/ (此处省略,可参考之前章节的代码) /*I2C.c 文件程序源代码***/ (此处省略,可参考之前章节的代码)

/*****************************main.c文件程序源代码******************************/#includebitflag300ms=1;//300ms定时标志unsignedcharT0RH=0;//T0重载值的高字节unsignedcharT0RL=0;//T0重载值的低字节voidConfigTimer0(unsignedintms);unsignedcharGetADCValue(unsignedcharchn);voidValueToString(unsignedchar*str,unsignedcharval);externvoidI2CStart();externvoidI2CStop();externunsignedcharI2CReadACK();externunsignedcharI2CReadNAK();externbitI2CWrite(unsignedchardat);externvoidInitLcd1602();externvoidLcdShowStr(unsignedcharx,unsignedchary,unsignedchar*str);voidmain(){unsignedcharval;unsignedcharstr[10];EA=1;//开总中断ConfigTimer0(10);//配置T0定时10msInitLcd1602();//初始化液晶LcdShowStr(0,0,"AIN0AIN1AIN3");//显示通道指示while(1){if(flag300ms){flag300ms=0;//显示通道0的电压val=GetADCValue(0);//获取ADC通道0的转换值ValueToString(str,val);//转为字符串格式的电压值LcdShowStr(0,1,str);//显示到液晶上//显示通道1的电压val=GetADCValue(1);ValueToString(str,val);LcdShowStr(6,1,str);//显示通道3的电压val=GetADCValue(3);ValueToString(str,val);LcdShowStr(12,1,str);}}}/*读取当前的ADC转换值,chn-ADC通道号0~3*/unsignedcharGetADCValue(unsignedcharchn){unsignedcharval;I2CStart();if(!I2CWrite(0x48<<1)){//寻址PCF8591,如未应答,则停止操作并返回0I2CStop();return0;}I2CWrite(0x40"chn);//写入控制字节,选择转换通道I2CStart();I2CWrite((0x48<<1)|0x01);//寻址PCF8591,指定后续为读操作I2CReadACK();//先空读一个字节,提供采样转换时间val=I2CReadNAK();//读取刚刚转换完的值I2CStop();returnval;}/*ADC转换值转为实际电压值的字符串形式,str-字符串指针,val-AD转换值*/voidValueToString(unsignedchar*str,unsignedcharval){//电压值=转换结果*2.5V/255,式中的25隐含了一位十进制小数val=(val*25)/255;str[0]=(val/10)+'0';//整数位字符str[1]='.';//小数点str[2]=(val%10)+'0';//小数位字符str[3]='V';//电压单位str[4]='';//结束符}/*配置并启动T0,ms-T0定时时间*/voidConfigTimer0(unsignedintms){unsignedlongtmp;//临时变量tmp=11059200/12;//定时器计数频率tmp=(tmp*ms)/1000;//计算所需的计数值tmp=65536-tmp;//计算定时器重载值tmp=tmp+12;//补偿中断响应延时造成的误差T0RH=(unsignedchar)(tmp>>8);//定时器重载值拆分为高低字节T0RL=(unsignedchar)tmp;TMOD&=0xF0;//清零T0的控制位TMOD|=0x01;//配置T0为模式1TH0=T0RH;//加载T0重载值TL0=T0RL;ET0=1;//使能T0中断TR0=1;//启动T0}/*T0中断服务函数,执行300ms定时*/voidInterruptTimer0()interrupt1{staticunsignedchartmr300ms=0;TH0=T0RH;//重新加载重载值TL0=T0RL;tmr300ms++;if(tmr300ms>=30){//定时300mstmr300ms=0;flag300ms=1;}}

细心阅读程序的同学会发现,程序在进行 A/D 读取数据的时候,共使用了两条程序去读了2个字节:I2CReadACK(); val = I2CReadNAK(); PCF8591 的转换时钟是 I2C 的 SCL,8个 SCL 周期完成一次转换,所以当前的转换结果总是在下一个字节的8个 SCL 上才能读出,因此我们这里第一条语句的作用是产生一个整体的 SCL 时钟提供给 PCF8591 进行 A/D 转换,第二次是读取当前的转换结果。如果我们只使用第二条语句的话,每次读到的都是上一次的转换结果。




              查看评论 回复



嵌入式交流网主页 > MCU > 单片机应用 > PCF8591 应用程序 -
 

"PCF8591 应用程序 -"的相关文章

网站地图

围观()