树莓派 pcf85911能够采集正弦波负半轴吗

PCF8591 DA驱动程序
> PCF8591 DA驱动程序
PCF8591 DA驱动程序
#include #include #include 本文引用地址:#define uchar unsigned char#define uint unsigned int#define disdata P0 //显示数据码输出口sbit SCL=P1^2; // 将p1.0口模拟时钟口sbit SDA=P1^3; // 将p1.3口模拟数据口sbit LCD_RS = P2^0;sbit LCD_RW = P2^1;sbit LCD_EN = P2^2;sbit K1 = P1^4;sbit K2 = P1^5; //选择健sbit K3 = P1^6; //启动健sbit K4 = P1^7; //停止健sbit BEEP = P3^6; //蜂鸣器uchar code dis1[] = {" PCF-8591 "};uchar code dis2[] = {" DA CONVERTER "};uchar code dis3[] = {" K2: D/A CHOOSE "};uchar code dis4[] = {"K3:ENTER K4:EXIT"};uchar code dis5[] = {" SINE WAVE "};uchar code dis6[] = {" SQUARE WAVE "};uchar code dis7[] = {" TRIANGLE WAVE "};uchar code dis8[] = {" SAWTOOTH WAVE "};bit out1=0,out2=0,out3=0,out4=0,START=0;#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};bit bdata SystemE //从机错误标志位uchar N=0x00,k_/*********************** PCF8591专用变量定义 ***********************/#definePCF8591_WRITE0x90#definePCF8591_READ 0x91#define NUM 4
//接收和发送缓存区的深度uchar idata receivebuf[NUM]; //数据接收缓冲区uchar code sin_tab[] = //正弦波输出表{ 0x80,0x83,0x86,0x89,0x8D,0x90,0x93,0x96,0x99,0x9C,0x9F,0xA2,0xA5,0xA8,0xAB,0xAE, 0xB1,0xB4,0xB7,0xBA,0xBC,0xBF,0xC2,0xC5,0xC7,0xCA,0xCC,0xCF,0xD1,0xD4,0xD6,0xD8, 0xDA,0xDD,0xDF,0xE1,0xE3,0xE5,0xE7,0xE9,0xEA,0xEC,0xEE,0xEF,0xF1,0xF2,0xF4,0xF5, 0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFD,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFD,0xFD,0xFC,0xFB,0xFA,0xF9,0xF8,0xF7,0xF6, 0xF5,0xF4,0xF2,0xF1,0xEF,0xEE,0xEC,0xEA,0xE9,0xE7,0xE5,0xE3,0xE1,0xDF,0xDD,0xDA, 0xD8,0xD6,0xD4,0xD1,0xCF,0xCC,0xCA,0xC7,0xC5,0xC2,0xBF,0xBC,0xBA,0xB7,0xB4,0xB1, 0xAE,0xAB,0xA8,0xA5,0xA2,0x9F,0x9C,0x99,0x96,0x93,0x90,0x8D,0x89,0x86,0x83,0x80, 0x80,0x7C,0x79,0x76,0x72,0x6F,0x6C,0x69,0x66,0x63,0x60,0x5D,0x5A,0x57,0x55,0x51, 0x4E,0x4C,0x48,0x45,0x43,0x40,0x3D,0x3A,0x38,0x35,0x33,0x30,0x2E,0x2B,0x29,0x27, 0x25,0x22,0x20,0x1E,0x1C,0x1A,0x18,0x16,0x15,0x13,0x11,0x10,0x0E,0x0D,0x0B,0x0A, 0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, 0x0A,0x0B,0x0D,0x0E,0x10,0x11,0x13,0x15,0x16,0x18,0x1A,0x1C,0x1E,0x20,0x22,0x25, 0x27,0x29,0x2B,0x2E,0x30,0x33,0x35,0x38,0x3A,0x3D,0x40,0x43,0x45,0x48,0x4C,0x4E, 0x51,0x55,0x57,0x5A,0x5D,0x60,0x63,0x66,0x69,0x6C,0x6F,0x72,0x76,0x79,0x7C,0x7E};/*******************************************************************//* *//* 延时函数 *//* *//*******************************************************************/void delayB(uchar x) //x*0.14MS{ while(x--) { for (i=0; i<13; i++) { } }}/*******************************************************************//* *//* 延时函数 *//* *//*******************************************************************/void delay(int ms){ while(ms--){ for(i=0;i<250;i++) { _nop_(); _nop_(); _nop_(); _nop_(); }}}/*******************************************************************//* *//* 蜂鸣器函数 *//* *//*******************************************************************/void beep(){ for (j=0;j<180;j++) { delayB(5); BEEP=!BEEP; //BEEP取反 } BEEP=1; //关闭蜂鸣器 delay(100);}/*******************************************************************//* *//*检查LCD忙状态 *//*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。 *//* *//*******************************************************************/bit lcd_busy(){ LCD_RS = 0; LCD_RW = 1; LCD_EN = 1; delayNOP(); result = (bit)(P0&0x80); LCD_EN = 0; return(result);}/*******************************************************************//* *//*写指令数据到LCD *//*RS=L,RW=L,E=高脉冲,D0-D7=指令码。 *//* *//*******************************************************************/void lcd_wcmd(uchar cmd){ while(lcd_busy()); LCD_RS = 0; LCD_RW = 0; LCD_EN = 0; _nop_(); _nop_(); P0 = delayNOP(); LCD_EN = 1; delayNOP(); LCD_EN = 0;}/*******************************************************************//* *//*写显示数据到LCD *//*RS=H,RW=L,E=高脉冲,D0-D7=数据。 *//* *//*******************************************************************/void lcd_wdat(uchar dat){ while(lcd_busy()); LCD_RS = 1; LCD_RW = 0; LCD_EN = 0; P0 = delayNOP(); LCD_EN = 1; delayNOP(); LCD_EN = 0;}/*******************************************************************//* *//* LCD初始化设定 *//* *//*******************************************************************/void lcd_init(){ delay(15); lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据 delay(5); lcd_wcmd(0x38); delay(5); lcd_wcmd(0x38); delay(5); lcd_wcmd(0x0c); //显示开,关光标 delay(5); lcd_wcmd(0x06); //移动光标 delay(5); lcd_wcmd(0x01); //清除LCD的显示内容 delay(5);}/*******************************************************************//* *//* 设定显示位置 *//* *//*******************************************************************/void lcd_pos(uchar pos){ lcd_wcmd(pos | 0x80); //数据指针=80+地址变量}//-------------------------------------------------------------------// 函数名称: iic_start()// 函数功能: 启动I2C总线子程序//-------------------------------------------------------------------void iic_start(void){ //时钟保持高,数据线从高到低一次跳变,I2C通信开始SDA = 1;SCL = 1;delayNOP(); // 延时5us SDA = 0;delayNOP(); SCL = 0;}//-------------------------------------------------------------------// 函数名称: iic_stop()// 函数功能: 停止I2C总线数据传送子程序//-------------------------------------------------------------------void iic_stop(void){SDA = 0;
//时钟保持高,数据线从低到高一次跳变,I2C通信停止SCL = 1;delayNOP();SDA = 1;delayNOP(); SCL = 0;}//------------------------------------------------------------------// 函数名称: iicInit_()// 函数功能: 初始化I2C总线子程序//------------------------------------------------------------------void iicInit(void) { SCL = 0; iic_stop(); }//-------------------------------------------------------------------// 函数名称: slave_ACK// 函数功能: 从机发送应答位子程序//-------------------------------------------------------------------void slave_ACK(void){SDA = 0;SCL = 1;delayNOP();SCL = 0;}//-------------------------------------------------------------------// 函数名称: slave_NOACK// 函数功能: 从机发送非应答位子程序,迫使数据传输过程结束//-------------------------------------------------------------------void slave_NOACK(void){SDA = 1;SCL = 1;delayNOP();SDA = 0; SCL = 0;}//-------------------------------------------------------------------// 函数名称: check_ACK// 函数功能: 主机应答位检查子程序,迫使数据传输过程结束//-------------------------------------------------------------------void check_ACK(void){ SDA = 1; // 将p1.1设置成输入,必须先向端口写1SCL = 1;flag = 0;delayNOP();if(SDA == 1) // 若SDA=1表明非应答,置位非应答标志flag flag = 1; SCL = 0;}//-------------------------------------------------------------------// 函数名称: IICSendByte// 入口参数: ch// 函数功能: 发送一个字节//-------------------------------------------------------------------void IICSendByte(uchar ch){ unsigned char idata n=8; // 向SDA上发送一位数据字节,共八位while(n--){if((ch&0x80) == 0x80) // 若要发送的数据最高位为1则发送位1 { SDA = 1; // 传送位1SCL = 1; delayNOP();//SDA = 0;SCL = 0; }else{SDA = 0; // 否则传送位0SCL = 1;delayNOP(); SCL = 0;}ch = ch<<1; // 数据左移一位}}//-------------------------------------------------------------------// 函数名称: IICreceiveByte// 返回接收的数据// 函数功能: 接收一字节子程序//-------------------------------------------------------------------uchar IICreceiveByte(void){uchar idata n=8; // 从SDA线上读取一上数据字节,共八位uchar tdata=0;while(n--){ SDA = 1; SCL = 1; tdata =tdata<<1; //左移一位 if(SDA == 1) tdata = tdata|0x01; // 若接收到的位为1,则数据的最后一位置1else tdata = tdata&0 // 否则数据的最后一位置0 SCL = 0; } return(tdata);}//-------------------------------------------------------------------// 函数名称: DAC_PCF8591// 入口参数: slave_add从机地址,n要发送的数据个数// 函数功能: 发送n位数据子程序//-------------------------------------------------------------------void DAC_PCF8591(uchar controlbyte){iic_start(); // 启动I2CdelayNOP();IICSendByte(PCF8591_WRITE); // 发送地址位check_ACK(); // 检查应答位 if(flag == 1) {SystemError = 1; // 若非应答,置错误标志位 } IICSendByte(controlbyte&0x77);//Control bytecheck_ACK(); //检查应答位 if(flag == 1) {SystemError = 1; // 若非应答,置错误标志位 }}//-------------------------------------------------------------------// 函数名称: ADC_PCF8591// 入口参数: controlbyte控制字// 函数功能: 连续读入4路通道的A/D转换结果到receivebuf//-------------------------------------------------------------------/*void ADC_PCF8591(uchar controlbyte){ //,receive_iic_start();IICSendByte(PCF8591_WRITE);//控制字check_ACK();if(flag == 1){SystemError = 1;}IICSendByte(controlbyte);//控制字check_ACK();if(flag == 1){SystemError = 1;} iic_start(); //重新发送开始命令 IICSendByte(PCF8591_READ);//控制字check_ACK();if(flag == 1){SystemError = 1;} IICreceiveByte(); //空读一次,调整读顺序 slave_ACK(); //收到一个字节后发送一个应答位//while(i<4) for(i=0;i<4;i++){// receive_da=IICreceiveByte();// receivebuf[i]=receive_ receivebuf[i] = IICreceiveByte(); slave_ACK(); //收到一个字节后发送一个应答位}slave_NOACK(); //收到最后一个字节后发送一个非应答位iic_stop();}*//********************************************************* 输出三角波*********************************************************/void Triangle(){ for(l=0;l<255;l++) { IICSendByte(l); //data byte check_ACK(); //检查应答位 if(flag == 1) {SystemError = 1; //置错误标志位SystemError } } for(l=255;l>1;l--) { IICSendByte(l); //data byte check_ACK(); //检查应答位 if(flag == 1) {SystemError = 1; //置错误标志位SystemError } }}/********************************************************* 输出方波函数*********************************************************/void Square(){ IICSendByte(N); //data byte check_ACK(); //检查应答位 if(flag == 1) { SystemError = 1; //置错误标志位SystemError } delay(15); N=~N;}/********************************************************* 输出正弦波函数*********************************************************/void sin(){ for(i=0; i<256; i++) { IICSendByte(sin_tab[i]); //data bytecheck_ACK(); //检查应答位 if(flag == 1) { SystemError = 1; //置错误标志位SystemError } }}/********************************************************* 输出锯齿波函数*********************************************************/void Sawtooth(){ for(l=0;l<255;l++) { IICSendByte(l); //data byte check_ACK(); //检查应答位 if(flag == 1) {SystemError = 1; //置错误标志位SystemError } }}/********************************************************* 功能健函数*********************************************************/void keyscan(){ if((K2==0)&(!START)) //启动输出后,屏蔽K2健 { k_count++; beep(); switch (k_count) { case 1: lcd_pos(0x00); for(m=0;m<16;m++) lcd_wdat(dis2[m]); lcd_pos(0x40); for(m=0;m<16;m++) lcd_wdat(dis5[m]); out1=1;out4=0; case 2: lcd_pos(0x40); for(m=0;m<16;m++) lcd_wdat(dis6[m]); out1=0;out2=1;case 3: lcd_pos(0x40); for(m=0;m<16;m++) lcd_wdat(dis7[m]);out2=0;out3=1; case 4: lcd_pos(0x40); for(m=0;m<16;m++) lcd_wdat(dis8[m]); k_count=0; out3=0;out4=1; default: out4=0; out3=0; out2=0; out1=0; } } if(K3==0) //启动输出{ START=1; beep();}if(K4==0) //停止输出{ START=0; beep();}}/*******************************************************************//* *//* 主函数 *//* *//*******************************************************************/main(){ delay(10); //延时 lcd_init(); //初始化LCD lcd_pos(0); //设置显示位置为第一行 for(i=0;i<16;i++) lcd_wdat(dis1[i]); //显示字符 lcd_pos(0x40); //设置显示位置为第二行 for(i=0;i<16;i++) lcd_wdat(dis2[i]); //显示字符 delay(1500); lcd_pos(0); //设置显示位置为第一行 for(i=0;i<16;i++) lcd_wdat(dis3[i]); //显示字符 lcd_pos(0x40); //设置显示位置为第二行 for(i=0;i<16;i++) lcd_wdat(dis4[i]); //显示字符DAC_PCF);while(1) { keyscan(); while(out1&START) { sin(); //输出正弦波 keyscan(); } while(out2&START) { Square(); //输出方波 keyscan(); } while(out3&START) { Triangle(); //输出三角波 keyscan(); } while(out4&START) { Sawtooth(); //输出锯齿波 keyscan(); } }}//*********************************************************
分享给小伙伴们:
我来说两句……
最新技术贴
微信公众号二
微信公众号一PCF8591在数据采集过程中的应用--《自动化应用》2015年10期
PCF8591在数据采集过程中的应用
【摘要】:使用软件模拟实现I2C总线4种典型信号的传输,对PCF8591外围电路进行设计,该电路结构简单,扩展性强。
【作者单位】:
【分类号】:TP273;TP274.2【正文快照】:
0引言I2C是一种多向控制总线,多个芯片可以连接同一总线结构下,同时每个芯片可以作为实施数据传输的控制源。I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上
欢迎:、、)
支持CAJ、PDF文件格式,仅支持PDF格式
【参考文献】
中国期刊全文数据库
周剑利,郭建波,崔涛;[J];微计算机信息;2005年07期
【共引文献】
中国期刊全文数据库
于新潮;刘玉婵;;[J];包头职业技术学院学报;2004年01期
李天倩;蔡育;;[J];成都纺织高等专科学校学报;2008年04期
刘文胜;;[J];长江工程职业技术学院学报;2008年03期
刘黎明;史进;刘慧环;;[J];电工技术;2002年11期
田红霞;杨金泉;;[J];电脑知识与技术;2008年34期
陶维青;李林;杨梅;;[J];电网技术;2006年S2期
薛立军;高满茹;;[J];低压电器;2008年21期
刘冰,杜道山,周士侃,李从心;[J];电子工程师;2004年09期
黄鑫;王玉林;谢静;;[J];仪器仪表用户;2010年04期
柯兰英;刘明;;[J];国外电子元器件;2008年11期
中国重要会议论文全文数据库
熊才高;;[A];湖北省机械工程学会设计与传动学会、武汉机械设计与传动学会2008年学术年会论文集(1)[C];2008年
陶维青;李林;杨梅;;[A];2006电力系统自动化学术交流研讨大会论文集[C];2006年
闫浩;钱伟康;刘少鹏;应怀樵;杜峰;;[A];第九届全国信号和智能信息处理与应用学术会议专刊[C];2015年
中国博士学位论文全文数据库
胡永华;[D];合肥工业大学;2001年
中国硕士学位论文全文数据库
马政;[D];中北大学;2011年
毕金虎;[D];延边大学;2011年
彭佛才;[D];西安电子科技大学;2001年
陈超录;[D];湖南大学;2001年
徐善锋;[D];西安电子科技大学;2002年
谢铿;[D];广东工业大学;2002年
程春雨;[D];大连理工大学;2002年
曾照福;[D];国防科学技术大学;2002年
童瑞华;[D];国防科学技术大学;2002年
韩军;[D];浙江大学;2002年
【相似文献】
中国期刊全文数据库
孙天泽,付晓江;[J];仪器仪表用户;2002年04期
,付晓江;[J];国外电子元器件;2002年11期
冒燕,李海鸿;[J];国外电子测量技术;2005年S1期
阳范青,曹剑中,刘波,杨小军;[J];航空计算技术;2005年02期
;[J];;年期
&快捷付款方式
&订购知网充值卡
400-819-9993查看: 66371|回复: 38
学51单片机-基于PCF8591的AD采样和DA输出
& && && && &首先思考一个问题,我们的世界是数字的还是模拟的?& && &当然是模拟的了,所有的量都是在一定范围内连续变化的。我们为了能够更加方便的描述这些量,对它们进行了数字化。而数字量就不一样了,它是分立的的几个值。& && &举个例子,我们形容一个人的身高,模拟的说法是一米七到一米七五之间,数字的说法就是一米七三。接下来说AD转换器,它的出现也是为了让我们能更方便、更直接的描述电压的高低。AD转换器,英文全称为Analog-to-Digital Converter,是模拟量到数字量的一个转换过程,主要用于电压的采集。它的出现就如同有了一把尺子,很容易就能量出电压的高低。在电子设备中,经常要检测各种模拟量:温度、压力、速度、流量、重力加速度等等,这些模拟量都被相应的传感器转换为电压信号,我们只需要测量电压的高低,就能得到相应参数。AD的主要参数有哪些?1、AD的位数:表明这个AD共有2^n个刻度,8位AD,输出的刻度是0~255.2、分辨率:就是AD能够分辨的最小的模拟量变化,假设5.10V的系统用8位的AD采样,那么它能分辨的最小电压就是5.10/255=0.02V。3、INL:Interger NONliner 积分非线性度,表示了ADC器件在所有的数值点上对应的模拟值,和真实值之间误差最大的那一点的误差值。也就是,输出数值偏离线性最大的距离。单位是LSB(即最低位所表示的量)。比如12位ADC:TLC2543,INL值为1LSB。那么,如果基准4.095V,测某电压得的转换结果是1000,那么,真实电压值可能分布在0.999~1.001V之间。4、DNL:Differencial NonLiner-差分非线性度,理论上说,模数器件相邻量个数据之间,模拟量的差值都是一样的。就相一把疏密均匀的尺子。但实际并不如此。一把分辨率1毫米的尺子,相邻两刻度之间也不可能都是1毫米整。那么,ADC相邻两刻度之间最大的差异就叫差分非线性值(Differencial NonLiner)。DNL值如果大于1,那么这个ADC甚至不能保证是单调的,输入电压增大,在某个点数值反而会减小。这种现象在SAR(逐位比较)型ADC中很常见。5、基准源:有内部基准源、外部基准源等等。6、转换速率:也就是转换周期的倒数,转换周期就是完成一次AD转换所需的时间。 今天要用到的器件是PCF8591,为什么选它?太多的开发板上用它做演示了,而且还是IIC总线通信的。既学习了AD采样,又学习了IIC总线。先上应用电路: & && &如上图所示,PCF8591的9脚和10脚,一个是数据线SDA,一个是时钟线SCL。分别接到单片机的P2.0 , P2.1上面。为什么选这两个引脚?因为51单片机上没有IIC总线接口,需要用普通的IO模拟,所以它随便选了两个IO接上就行。VREF是什么?基准电压,也是它能测量的最大电压。如何控制?今天先不说IIC总线,只说控制流程。看器件手册可以知道: 分四步:1、发送地址字节,选择该器件。2、发送控制字节,选择相应通道。& && && && && &//3、重新发送地址字节,选择该器件。4、接收目标通道的数据。 这次的程序流程是:AD采样,串口发送,循环执行。下面是AD采样源代码:/**********************51单片机学习例程************************
*&&平台:Keil U4 + STC89C52
*&&名称:AD采样+串口发送
*&&编写:起航
*&&晶体:11.0592MHZ
******************************************************************/
#include &reg52.h&
#include &intrins.h&
typedef unsigned char uint8;
typedef unsigned int uint16;
#define SLAVEADDR&&0x90& & & & & & & &&&//定义器件地址
#define nops()&&do{_nop_();_nop_();_nop_();_nop_();_nop_();} while(0) //定义空指令
sbit SCL = P2^1;& && & //I2C&&时钟
sbit SDA = P2^0;& && & //I2C&&数据
void delay(uint16 n)
{
& & & & while (n--);
}
/**
* 函数: i2c_start()
* 功能: 启动i2c& & & & & & & && &起始信号
*/
void i2c_start()
{
& & & & SCL = 1;
& & & & nops();
& & & & SDA = 1;
& & & & nops();
& & & & SDA = 0;
& & & & nops();
& & & & SCL = 0;
}
* 函数: i2c_stop()
* 功能: 停止i2c
*/
void i2c_stop()
{
& & & & SCL = 0;
& & & & nops();
& & & & SDA = 0;
& & & & nops();
& & & & SCL = 1;
& & & & nops();
& & & & SDA = 1;
& & & & nops();
}
* 函数: i2c_ACK(bit ck)
* 功能: ck为1时发送应答信号ACK,
*& && & ck为0时不发送ACK
*/
void i2c_ACK(bit ck)
{
& & if (ck)
& & & & & & & & SDA = 0;
& & else
& & & & & & & & SDA = 1;
& & nops();
& & SCL = 1;
& & nops();
& & SCL = 0;
& & & & nops();
& & SDA = 1;
& & nops();
}
* 函数: i2c_waitACK()
* 功能: 返回为0时收到ACK
*& && & 返回为1时没收到ACK
*/
bit i2c_waitACK()
{
& & & & SDA = 1;
& & & & nops();
& & & & SCL = 1;
& & & & nops();
& & & & if (SDA)
& & & & {& &
& & & & & & & & SCL = 0;
& & & & & & & & i2c_stop();
& & & & & & & & return 1;
& & & & }
& & & & else
& & & & {&&
& & & & & & & & SCL = 0;
& & & & & & & & return 0;
& & & & }
}
* 函数: i2c_sendbyte(uint8 bt)
* 功能: 将输入的一字节数据bt发送
*/
void i2c_sendbyte(uint8 bt)
{
& & uint8
& &
& & for(i=0; i&8; i++)
& & {&&
& && &&&if (bt & 0x80)
& & & & & & & & & & & & SDA = 1;
& && &&&else
& & & & & & & & & & & & SDA = 0;
& && &&&nops();
& && &&&SCL = 1;
& && &&&bt &&= 1;
& && &&&nops();& && &
& && &&&SCL = 0;
& & }
}
* 函数: i2c_recbyte( )
* 功能: 从总线上接收1字节数据
*/
uint8 i2c_recbyte()
{
& & & & uint8 dee,
& & & &
& & & & for (i=0; i&8; i++)
& & & & {
& & & & & & & & SCL = 1;& &
& & & & & & & & nops();
& & & & & & & & dee &&= 1;
& & & & & & & & if (SDA)
& & & & & & & & & & & & dee = dee | 0x01;
& & & & & & & & SCL = 0;
& & & & & & & & nops();
& & & & }
& & & &
* 函数: i2c_readbyte
* 输入: addr
* 功能: 读出一字节数据
* 返回值: 0-&成功&&1-&失败
*/
bit i2c_readbyte(uint8 com, uint8 *dat)
{& & & &
& & & & i2c_start();
& & & & i2c_sendbyte(SLAVEADDR);& & //地址
& & if (i2c_waitACK())
& & & & & & & & return 1;
& & & & i2c_sendbyte(com);& && &&&//控制字节
& & if (i2c_waitACK())
& & & & & & & & return 1;
& & & & i2c_start();
& & & & i2c_sendbyte(SLAVEADDR+1); //地址
& & if (i2c_waitACK())
& & & & & & & & return 1;
& & & & *dat = i2c_recbyte();& && &//读数据
& & & & i2c_ACK(0);& && && && && & //因为只读一字节数据,不发送ACK信号
& & & & i2c_stop();& &
& & & &
& & & & return 0;
}
* UART初始化
* 波特率:9600
*/
void uart_init(void)
{
& & ET1=0;
& & TMOD = 0x21;& && &&&// 定时器1工作在方式2(自动重装)
& & SCON = 0x50;& && &&&// 10位uart,允许串行接受
& & TH1 = 0xFD;
& & TL1 = 0xFD;
& & TR1 = 1;
}
* UART 发送一字节
*/
void UART_Send_Byte(uint8 dat)
{
& & & & SBUF =
& & & & while (TI == 0);
& & & & TI = 0;
}
main()
{
& & & & uint8
& & & & uart_init();
& & & & while(1)
& & & & {
& & & & & & & & i2c_readbyte(0x43, &ans);
& & & && &&&
& & & & & & & & UART_Send_Byte(ans);
& & & & & & & & delay(50000);
& & & & }
}
复制代码本程序下载链接(附带PCF8591中文资料pdf资料):
(459.16 KB, 下载次数: 542)
22:46 上传
点击文件名下载附件
下载积分: 黑币 -5
-------------------------------------------------------------------------------------
下面介绍PCF8591的DA输出:
& && &忽然发现,已经写到AD/DA这里来了。严格来说,已经不是51单片机的内容了,而是周边应用电路的一些东西。这些东西涉及的知识面比较广,什么都有可能提到。& && &关于AD/DA,或者其它设备,我的学习思路是先模仿,再深究。& && &因为无论是课本也好,器件手册也好,大部分讲的都是原理或者寄存器,起到的是一个工具书的作用,类似于语文课上用的字典。但是这就出现了一个问题,很多人想通过看课本或者看器件手册的方式来掌握这些设备。& && &这个思路有问题吗?没有问题吗?& && &还记得我刚才说的话么,它们就类似于语文课上用的字典,但是,有谁是通过看字典学会说话的!!!& && &我们都是通过模仿别人学会说话的,遇到不认识的字才去查字典!但是很多人或者很多学校都把这两件事的顺序搞反了。& && &记得之前我在英飞凌官网进行芯片选型,网页都翻烂了,找不到合适的。因为英飞凌不是我家开的,我不能保证每次都能顺利的找到我想要的东西。& && &但是,我同事参加了一次电子展,在展会上遇到了英飞凌的展台,然后问他们,他们一听我们的需求,马上找出一堆能满足我们要求的芯片。& && &这就是思路的问题!& && &扯远了,说回到DA控制。DA转换(Digital to Analog),是将数字量变成模拟量的一个过程。AD与DA刚好是相反的两个过程,AD是把模拟信号变成单片机可识别的数字信号;DA是把单片机可识别的数字信号变成连续变化的模拟量。这两种功能的应用范围都非常广泛!& && &主要参数如下,具体什么意思就不讲了,大家可以百度一下。(因为我编不出来了...)1)分辩率(Resolution)2) 转换速率(Conversion Rate)3)量化误差 (Quantizing Error)4)偏移误差(Offset Error)5)满刻度误差(Full Scale Error)6)线性度(Linearity)其他指标还有:绝对精度(Absolute Accuracy) ,相对精度(Relative Accuracy),微分非线性,单调性和无错码,总谐波失真(Total Harmonic Distotortion缩写THD)和积分非线性。看到这么多参数,是不是很晕?搞了这些年电子,感触最深的有一点是:无论做什么,先求有,再求好!不要总想一口吃个胖子,没那么多天才。参数是很多,但是没要求你一下子全都记住,甚至你可以只记一两个。先把大致的应用流程跑一遍,跑下来,你才对这个设备有一个整体的概念,然后针对你的要求,比对相应的参数,进行修改、调试。哪怕是在工作中,也不一定会考虑全部的参数。例如转换时间,我到现在也没认真看PIC内部的AD采样转换时间有多久,因为有些设备对实时性要求很低,速度慢一些也没事。然后是控制流程,认真看器件手册的,或者看了昨天日志的,都知道是怎样一个流程:第一步:写器件地址;第二步:写控制位。第三步:写入数据。 好了,上程序。通过DA输出渐变电压控制LED,形成呼吸灯的效果。里面有个警告:*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS& && &大家可以研究下,如何消除警告。程序源码如下:/**********************51单片机学习例程************************
*&&平台: Keil U34 + STC89C52RD
*& & & &&&名称:IIC协议 PCF8591ADDA转换& & & & ,此程序通过IIC协议对DAAD芯片操作, 并输出模拟量,用LED亮度渐变指示
*&&编写:起航
*&&晶振:11.0592MHZ
******************************************************************/
#include&reg52.h&& & //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include &intrins.h& //包含NOP空指令函数_nop_();
#define AddWr 0x90& &//写数据地址
#define AddRd 0x91& &//读数据地址
sbit RST=P2^4;& &//关掉时钟芯片输出
sbit Sda=P2^0;& && &//定义总线连接端口
sbit Scl=P2^1;
sbit Fm=P2^3;& & & && &//FM
sbit dula=P2^6;
sbit wela=P2^7;
// bit ADF& && && & //定义AD采样标志位
unsigned char code Datatab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//7段数共阴码管段码表
data unsigned char&&Display[8];//定义临时存放数码管数值
/*------------------------------------------------
& && && && && && &&&延时程序
------------------------------------------------*/
void mDelay(unsigned char j)
{
&&
&&for(;j&0;j--)
& &&&{
& & & && &for(i=0;i&125;i++)
& & & && && &{;}
& & & && &}
&&}
/*------------------------------------------------
& && && && && && &&&初始化定时器1
------------------------------------------------*/
void Init_Timer1(void)
{
TMOD |= 0x10;& & & & & & & & & & & && && &
TH1=0& & & && && && && && && & & & /* Init value */
//PT1=1;& && && && && && & /* 优先级& & */
EA=1;& && && && && && && & /* interupt enable */
ET1=1;& && && && && && && &/* enable timer1 interrupt */
TR1=1;&&
}
/*------------------------------------------------
& && && && && && &&&启动IIC总线
------------------------------------------------*/
&&void Start(void)
&&{
& &Sda=1;
& &_nop_();
& &Scl=1;
& &_nop_();
& &Sda=0;
& &_nop_();
& &Scl=0;
&&}
/*------------------------------------------------
& && && && && && &&&停止IIC总线
------------------------------------------------*/
&&void Stop(void)
&&{
& &Sda=0;
& &_nop_();
& &Scl=1;
& &_nop_();
& &Sda=1;
& &_nop_();
& &Scl=0;
& &}
/*------------------------------------------------
& && && && && && & 应答IIC总线
------------------------------------------------*/
& &void Ack(void)
& &{
& & Sda=0;
& & & & _nop_();
& & & & Scl=1;
& & & & _nop_();
& & & & Scl=0;
& & & & _nop_();
& & & & }
/*------------------------------------------------
& && && && &&&发送一个字节
------------------------------------------------*/
& & & &&&void Send(unsigned char Data)
& & & &&&{
& & & && &unsigned char BitCounter=8;
& & & && &
& & & && &do
& & & && &&&{
& & & & & & & &&&temp=D
& & & & & & & &&&Scl=0;
& & & & & & & &&&_nop_();
& & & & & & & &&&if((temp&0x80)==0x80)
& & & & & & & && &&&Sda=1;
& & & & & & & &&&else
& & & & & & & && &&&Sda=0;
& & & & & & & & & & & & Scl=1;
& & & & & & & & & & & & temp=Data&&1;
& & & & & & & & & & & & Data=
& & & & & & & & & & & & BitCounter--;
& & & & & & & && &}
& & & && &while(BitCounter);
& & & && && & Scl=0;
& & & && &}
/*------------------------------------------------
& && && && && && &&&写入DA数模转换值
------------------------------------------------*/
& & & && &void DAC(unsigned char Data)
& & & && &{
& & & & & & & && & Start();
& & & & & & & && & Send(AddWr); //写入芯片地址
& & & & & & & && & Ack();
& & & & & & & && & Send(0x40);&&//写入控制位,使能DAC输出
& & & & & & & && & Ack();
& & & & & & & && & Send(Data);&&//写数据
& & & & & & & && & Ack();
& & & & & & & && & Stop();
& & & & & & & &&&
& & & && & }
& & & & void fmg(void)//fm关
& & & & {& & & &
& & & & Fm=1;& & & & //& & & & & & & & 关 fm
& & & & }
& & & & & & & &&&void cmg(void)//数码管锁存函数& & & & & & & && & 关时钟DS1302
& & & & {
& & & & dula=1;
& & & & P0=0x00;
& & & & dula=0;
& & & & wela=1;
& & & & P0=0x00;
& & & & wela=0;
& & & & RST=0;& & & & & & & & //& & & & & & & & 关时钟DS1302
& & & & }
/*------------------------------------------------
& && && && && && & 主程序
------------------------------------------------*/
& & & & void main()
& & & & {
& & & &&&& && && && && && & //DA数模输出变量
& &Init_Timer1();
& & & &&&cmg();//数码管锁存
& & & &&&fmg();
& & & &&&while(1)
& & & && & {
& && & DAC(num);& && & //DA输出,可以用LED模拟电压变化
& & & & & & & && & num++;& && && & //累加,到256后溢出变为0,往复循环。显示在LED上亮度逐渐变化
& & & & & & & && & mDelay(20);& &&&//延时用于清晰看出变化
& & & && & }
& & & & }
复制代码下载链接:
(29.03 KB, 下载次数: 183)
22:46 上传
点击文件名下载附件
下载积分: 黑币 -5
请问楼主,PCF8591适合做心电信号的AD采样吗?求指导啊
请问那个AD转换实例实现的功能是采集什么数据啊&
看了一下,刚学哎
正在学习AD/DA!谢谢
不错,正在学ad/da
很好很强大
//unsigned char code Datatab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//data unsigned char&&Display[8];
警告应该是因为这两句是多余的
楼主,我是小白。收获好多,谢谢
很好的东西~谢谢楼主
很好的东西,谢谢楼主
& & 请问“发送一个字节”这一段程序是干啥用的,为啥要用着个程序呢,谢谢我是小白
很好的东西~谢谢楼主
刚开始学数模转换,谢谢楼主啦。
深度好贴,谢谢楼主了。
很好的文章,刚好要用……
楼主东西很好,对我帮助很大
学习了,学习了,感谢楼主
楼主,这两个圈里的器件指的应该是同一个器件吧?那为什么第152行代码中器件地址是SLAVEADDR,而第159行代码中器件地址是SLAVEADDR+1?为什么要加1呢?
我突然明白了,152行的SLAVEADDR是要写,159行的SLAVEADDR+1是要读,所以要加1
学习了,谢谢!
DA输出之前没怎么了解&&今天恶补&&谢谢
谢谢分享!!
很好,十分有用。感谢分享。
请问,你们有遇到DA输出的时候电压不够的情况吗?测到VCC有5.19V,但是输出最大只能到4.42V,
请问转换周期怎么计算,或者说具体采样频率怎么计算
PCF8591和PCF8591T有什么区别吗?是不是管脚不同?
楼主威武&&楼主万岁万岁万万岁
终于在这找到了,正需要
貌似很不错
没有黑币啊,好苦恼。。。。。。。
w2 w3是什么东西??
很给力!!
谢谢楼主,毕设正好需要这个器件
谢谢楼主,!!!
请问,我没加上拉电阻,数值一直在跳,等我加上上拉电阻,求平均值后&&数据会稳定下来吗
Powered by

我要回帖

更多关于 pcf8591时序 的文章

 

随机推荐