PCF8591_DA和AD转换器读写程序
实验(二)DA转换实验

实验二D/ A转化实验一、实验目的:(1)掌握D/A转换与单片机的接口方法。
(2)了解D/A芯片PCF8591转换性能及编程方法。
(3)了解单片机系统中扩展D/ A转换芯片的基本方法二、实验内容利用实验仪上的PCF8591做D/A转换实验,写入DA的数模值,然后累加该值,显示该值到数码管,延时100m后循环写入变化后的DA值,观察LED9的变化。
三、实验说明A/ D转换器大致分有三类:一是双积分A/ D转换器,优点是精度高,抗干扰性好,价格便宜,但速度慢;二是逐次逼近式A/ D转换器,精度、速度、价格适中;三是并行A/ D 转换器,速度快,价格也昂贵。
PCF8591属第二类,PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。
PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。
PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。
在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。
四、实验步骤(1)单片机P0口与J3相连,用作数码管显示(2)单片机P2.2与J2(B)相连,P2.2与J2(A)相连。
(3)跳帽J50 连接,给数码管供电。
(4)单片机P2.0与J8(SCL)相连,最为时钟输出,单片机P2.1与J8(SDL)相连最为数据输入输出。
(5)J31中AD0与W4用跳帽相连,选择AD通道。
(6)利用keil软件编写程序,并且用STC程序下载工具下载程序。
(7)观察LED9的变化。
基于51单片机的AD和DA

基于51单片机的AD和DA本讲内容:介绍AD/DA芯片PCF8591,通过例程讲解AD和DA过程。
AD和DA的概念:AD转换的功能是把模拟量电压转换为数字量电压。
DA转换的功能正好相反,就是讲数字量转换位模拟量。
分辨率的概念:一位数字量所表示的电压值。
对于5V的满量程,采用8位的DAC 时,分辨率为5V/256=19.5mV。
PCF8591简介:PCF8591是单片、单电源低功耗8位CMOS数据采集器件,具有4个模拟输入、一个模拟输出和一个串行IIC总线接口。
3个地址引脚A0、A1和A2用于编程硬件地址,允许将最多8个器件连接至IIC总线而不需要额外硬件。
PCF8591管脚图:PCF8591接口电路图:PCF8591的控制寄存器:例程:AD程序/**********************AD转换**********************单片机型号:STC89C52RC*开发环境:KEIL*功能:IIC协议 PCF8591 AD转换**************************************************/#include<reg52.h>#include <intrins.h>#define LCD_Data P0#define Busy 0x80#define uchar unsigned char#define delay0;_nop_();#define AddWr 0x90#define AddRd 0x91sbit RST=P2^4;sbit Sda=P2^0;sbit Scl=P2^1;sbit LCD_RS=P1^0;sbit LCD_RW=P1^1;sbit LCD_E =P2^5;bit ADFlag;uchar code table0[]={" SL-51A "};uchar code table1[]={" AD CONVERT "};uchar code table2[]={"CH1: . V"};uchar code table3[]={"CH2: . V"};uchar code table4[]={"CH3: . V"};uchar code table5[]={"CH4: . V"};uchar TempData[8];void Delay5Ms(void);void delay(int In,int Out); void WriteDataLCD(unsigned char WDLCD);void WriteCommandLCD(unsigned char WCLCD,BuysC);uchar ReadDataLCD(void);uchar ReadStatusLCD(void);void LCDInit(void);void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData);void DisplayListChar(unsigned char X,unsigned char Y,unsigned char code *DData);void Init_Timer1(void);void Start(void);void Stop(void);void Ack(void);void NoAck(void);void Send(unsigned char Data);uchar Read(void);void DAC(unsigned char Data);uchar ReadADC(unsigned char Chl);void info_disp(void);/**********5ms延时函数***************************/void Delay5Ms(void){unsigned int TempCyc=3552;while(TempCyc--);}/********************延迟函数********************/void delay(int In,int Out) {int i,j;for(i=0;i<In;i++){for(j=0;j<Out;j++){;}}}/*------------------------------------------------初始化定时器1------------------------------------------------*/void Init_Timer1(void){TMOD|=0x10;TH1=0xff;TL1=0x00;EA=1;ET1=1;TR1=1;}/*------------------------------------------------启动IIC总线------------------------------------------------*/void Start(void){Sda=1;delay0;Scl=1;delay0;Sda=0;delay0;Scl=0;}/*------------------------------------------------停止IIC总线------------------------------------------------*/void Stop(void){Sda=0;delay0;Scl=1;delay0;Sda=1;delay0;Scl=0;}/*------------------------------------------------应答IIC总线------------------------------------------------*/void Ack(void){Sda=0;delay0;Scl=1;delay0;Scl=0;delay0;}/*------------------------------------------------非应答IIC总线------------------------------------------------*/void NoAck(void){Sda=1;delay0;Scl=1;delay0;Scl=0;delay0;}/*------------------------------------------------发送一个字节------------------------------------------------*/ void Send(unsigned char Data){uchar BitCounter=8;uchar temp;do{temp=Data;Scl=0;delay0;if((temp&0x80)==0x80){Sda=1;}else{Sda=0;}Scl=1;temp=Data<<1;Data=temp;BitCounter--;}while(BitCounter);Scl=0;}/*------------------------------------------------读入一个字节并返回------------------------------------------------*/ uchar Read(void){uchar temp=0;uchar temp1=0;uchar BitCounter=8;Sda=1;do{Scl=0;delay0;Scl=1;delay0;if(Sda){temp=temp|0x01;}else{temp=temp&0xfe;}if(BitCounter-1){temp1=temp<<1;temp=temp1;}BitCounter--;}while(BitCounter);return(temp);}/*------------------------------------------------写入DA数模转换值------------------------------------------------*/ void DAC(unsigned char Data){Start();Send(AddWr);Ack();Send(0x40);Ack();Send(Data);Ack();Stop();}/*------------------------------------------------读取AD模数转换的值,有返回值------------------------------------------------*/ uchar ReadADC(unsigned char Chl){uchar Data;Start();Send(AddWr);Ack();Send(0x40|Chl);Ack();Start();Send(AddRd);Ack();Data=Read();Scl=0;NoAck();Stop();return Data;}/*******************写数据函数*******************/ void WriteDataLCD(unsigned char WDLCD){ReadStatusLCD();LCD_Data=WDLCD;LCD_RS=1;LCD_RW=0;LCD_E=0;LCD_E=0;LCD_E=1;}/*******************写指令函数*******************/ void WriteCommandLCD(unsigned char WCLCD,BuysC) {if(BuysC)ReadStatusLCD();LCD_Data=WCLCD;LCD_RS=0;LCD_RW=0;LCD_E=0;LCD_E=0;LCD_E=1;}/*******************读数据函数*******************/unsigned char ReadDataLCD(void){LCD_RS=1;LCD_RW=1;LCD_E=0;LCD_E=0;LCD_E=1;return(LCD_Data);}/*******************读状态函数*******************/unsigned char ReadStatusLCD(void){LCD_Data=0xFF;LCD_RS=0;LCD_RW=1;LCD_E=0;LCD_E=0;LCD_E=1;while (LCD_Data&Busy);return(LCD_Data);}/********************LCD初始化*******************/void LCDInit(void){LCD_Data=0;WriteCommandLCD(0x38,0);Delay5Ms();WriteCommandLCD(0x38,0);Delay5Ms();WriteCommandLCD(0x38,0);Delay5Ms();WriteCommandLCD(0x38,1);WriteCommandLCD(0x08,1);WriteCommandLCD(0x01,1);WriteCommandLCD(0x06,1);WriteCommandLCD(0x0C,1);}/********************清屏函数********************/void LCD_Clear(void){WriteCommandLCD(0x01,1);Delay5Ms();}/**************按指定位置显示一个字符*************/void DisplayOneChar(unsigned char X,unsigned char Y,unsigned char DData) {Y&=0x1;X&=0xF;if(Y)X|=0x40;X|=0x80;WriteCommandLCD(X, 0);WriteDataLCD(DData);}/**************按指定位置显示一串字符*************/void DisplayListChar(unsigned char X,unsigned char Y,unsigned char code *DData) {unsigned char ListLength;ListLength=0;Y&=0x1;X&=0xF;while(DData[ListLength]>=0x20){if(X<=0xF){DisplayOneChar(X, Y, DData[ListLength]);ListLength++;X++;}}}/********************系统初始化*******************/void sys_init(void){LCDInit();delay(5,100);Init_Timer1();DisplayListChar(0,0,table0);DisplayListChar(0,1,table1);}/*------------------------------------------------显示------------------------------------------------*/void info_disp(void){DisplayListChar(0,0,table2);DisplayOneChar(4,0,(0x30+TempData[0]));DisplayOneChar(6,0,(0x30+TempData[1]));DisplayListChar(8,0,table3);DisplayOneChar(12,0,(0x30+TempData[2]));DisplayOneChar(14,0,(0x30+TempData[3]));DisplayListChar(0,1,table4);DisplayOneChar(4,1,(0x30+TempData[4]));DisplayOneChar(6,1,(0x30+TempData[5]));DisplayListChar(8,1,table5);DisplayOneChar(12,1,(0x30+TempData[6]));DisplayOneChar(14,1,(0x30+TempData[7]));}/*------------------------------------------------主程序------------------------------------------------*/void main(){uchar num;uchar ADtemp;sys_init();delay(100,1000);LCD_Clear();while(1){DAC(num);num++;delay(5,100);if(ADFlag){ADFlag=0;ADtemp=ReadADC(0);TempData[0]=(ReadADC(0))/50;TempData[1]=((ReadADC(0))%50)/10; ADtemp=ReadADC(1);TempData[2]=(ReadADC(1))/50;TempData[3]=((ReadADC(1))%50)/10; ADtemp=ReadADC(2);TempData[4]=(ReadADC(2))/50;TempData[5]=((ReadADC(2))%50)/10; ADtemp=ReadADC(3);TempData[6]=(ReadADC(3))/50;TempData[7]=((ReadADC(4))%50)/10; info_disp();}}}/*------------------------------------------------定时器中断程序------------------------------------------------*/void Timer1_isr(void) interrupt 3 using 1{static unsigned int j;TH1=0xfb;TL1=0x00;j++;if(j==200){j=0;ADFlag=1;}}DA程序/******************DA转换LED输出*******************单片机型号:STC89C52RC*开发环境:KEIL*功能:此程序通过IIC协议对DAAD芯片操作, 并输出模拟量,用LED亮度渐变指示***************************************************/#include<reg52.h>#include <intrins.h>#define delay0; _nop_();#define uchar unsigned char#define AddWr 0x90#define AddRd 0x91sbit RST=P2^4;sbit Sda=P2^0;sbit Scl=P2^1;sbit Fm=P2^3;sbit LE1=P2^6;sbit LE2=P2^7;bit ADFlag;uchar code Datatab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; data uchar Display[8];/*------------------------------------------------延时程序------------------------------------------------*/void mDelay(uchar j){unsigned int i;for(;j>0;j--){for(i=0;i<125;i++){;}}}/*------------------------------------------------初始化定时器1------------------------------------------------*/void Init_Timer1(void){TMOD|=0x10;TH1=0xff;TL1=0x00;EA=1;ET1=1;TR1=1;}/*------------------------------------------------启动IIC总线------------------------------------------------*/void Start(void){Sda=1;delay0;Scl=1;delay0;Sda=0;delay0;Scl=0;}/*------------------------------------------------停止IIC总线------------------------------------------------*/ void Stop(void){Sda=0;delay0;Scl=1;delay0;Sda=1;delay0;Scl=0;}/*------------------------------------------------应答IIC总线------------------------------------------------*/ void Ack(void){Sda=0;delay0;Scl=1;delay0;Scl=0;delay0;}/*------------------------------------------------非应答IIC总线------------------------------------------------*/ void NoAck(void){Sda=1;delay0;Scl=1;delay0;Scl=0;delay0;}/*------------------------------------------------发送一个字节------------------------------------------------*/ void Send(uchar Data){uchar BitCounter=8;uchar buffer;do{buffer=Data;Scl=0;delay0;if((buffer&0x80)==0x80)Sda=1;else Sda=0;Scl=1;buffer=Data<<1;Data=buffer;BitCounter--;}while(BitCounter);Scl=0;}/*------------------------------------------------读入一个字节并返回------------------------------------------------*/ uchar Read(void){uchar buffer=0;uchar buffer1=0;uchar BitCounter=8;Sda=1;do{Scl=0;delay0;Scl=1;delay0;if(Sda)buffer=buffer|0x01;else buffer=buffer&0xfe;if(BitCounter-1){buffer1=buffer<<1;buffer=buffer1;}BitCounter--;}while(BitCounter);return(buffer);}/*------------------------------------------------写入DA数模转换值------------------------------------------------*/ void DAC(uchar Data){Start();Send(AddWr);Ack();Send(0x40);Ack();Send(Data);Ack();Stop();}/*------------------------------------------------读取AD模数转换的值,有返回值------------------------------------------------*/ uchar ReadADC(uchar Chl){uchar Data;Start();Send(AddWr);Ack();Send(0x40|Chl);Ack();Start();Send(AddRd);Ack();Data=Read();Scl=0;NoAck();Stop();return Data;}void fmg(void){Fm=1;}void cmg(void){LE1=1;P0=0x00;LE1=0;LE2=1;P0=0x00;LE2=0;RST=0;}/*------------------------------------------------主程序------------------------------------------------*/ void main(){uchar num;uchar ADbuffer;Init_Timer1();cmg();fmg();while(1){DAC(num);num++;mDelay(20);if(ADFlag){ADFlag=0;ADbuffer=ReadADC(0);Display[0]=Datatab[(ReadADC(0))/50]|0x80;Display[1]=Datatab[((ReadADC(0))%50)/10];ADbuffer=ReadADC(1);Display[2]=Datatab[((ReadADC(1))/50)]|0x80;Display[3]=Datatab[((ReadADC(1))%50)/10];ADbuffer=ReadADC(2);Display[4]=Datatab[((ReadADC(2))/50)]|0x80;Display[5]=Datatab[((ReadADC(2))%50)/10];ADbuffer=ReadADC(3);Display[6]=Datatab[((ReadADC(3))/50)]|0x80; Display[7]=Datatab[((ReadADC(3))%50)/10]; }}}。
PCF8591模数与数模转换实验

源程序:#include <reg52.h>#include <intrins.h>#define uint unsigned int#define uchar unsigned char#define Delay4us() {_nop_();_nop_();_nop_();_nop_();}sbit LCD_RS = P2^0;sbit LCD_RW = P2^1;sbit LCD_EN = P2^2;sbit SCL = P1^0;sbit SDA = P1^1;uchar Recv_Buffer[4];uint V oltage[]={'0','0','0','0'};bit bdata IIC_ERROR;uchar LCD_Line_1[] = {"1- . V 2- . V"}; uchar LCD_Line_2[] = {"3- . V 4- . V"};void Delay(uint ms){uchar i;while(ms--){for(i=0;i<120;i++)Delay4us();}}bit LCD_Busy_Check(){bit Result;LCD_RS = 0;LCD_RW = 1;LCD_EN = 1;Delay4us();Result = (bit)(P0&0x80);LCD_EN = 0;return Result;}void LCD_Write_Command(uchar cmd) {while(LCD_Busy_Check());LCD_RS = 0;LCD_RW = 0;LCD_EN = 0;_nop_();_nop_();P0 = cmd;Delay4us();LCD_EN = 1;Delay4us();LCD_EN = 0;}void LCD_Write_Data(uchar dat){while(LCD_Busy_Check());LCD_RS = 1;LCD_RW = 0;LCD_EN = 0;P0 = dat;Delay4us();LCD_EN = 1;Delay4us();LCD_EN = 0;}void LCD_Initialise(){LCD_Write_Command(0x38);Delay(5);LCD_Write_Command(0x0c);Delay(5);LCD_Write_Command(0x06);Delay(5);LCD_Write_Command(0x01);Delay(5);}void LCD_Set_Position(uchar pos){LCD_Write_Command(pos | 0x80);}void LCD_Display_A_Line(uchar Line_Addr,uchar s[]){uchar i;LCD_Set_Position(Line_Addr);for(i=0;i<16;i++){LCD_Write_Data(s[i]);}}// 将模数转换后得到的值分解存入缓存void Convert_To_V oltage(uchar val){uchar Tmp; //最大值为255,对应5V,255/5=51 V oltage[2] = val/51+'0'; //整数部分Tmp = val%51*10; //第一位小数V oltage[1] = Tmp/51+'0';Tmp = Tmp%51*10;V oltage[0] = Tmp/51+'0';}void IIC_Start() {SDA = 1;SCL = 1;Delay4us();SDA = 0;Delay4us();SCL = 0;}void IIC_Stop() {SDA = 0;SCL = 1;Delay4us();SDA = 1;Delay4us();SCL = 0;}void Slave_ACK() {SDA = 0;SCL = 1;Delay4us();SCL = 0;SDA = 1;}void Slave_NOACK(){SDA = 1;SCL = 1;Delay4us();SCL = 0;SDA = 0;}void IIC_SendByte(uchar wd){uchar i;for(i=0;i<8;i++){SDA=(bit)(wd&0x80);_nop_();_nop_();SCL = 1;Delay4us();SCL=0;wd<<=1;}Delay4us();SDA = 1;SCL = 1;Delay4us();IIC_ERROR = SDA; //IIC_ERROR=1表示无应答SCL = 0;Delay4us();}uchar IIC_ReceiveByte(){uchar i,rd = 0x00;for(i=0;i<8;i++){SCL = 1;rd <<= 1;rd |= SDA;Delay4us();SCL = 0;Delay4us();}SCL = 0;Delay4us();return rd;}//连续读入4路通道的A/D转换结果并保存到Recv_Buffer void ADC_PCF8591(uchar CtrlByte){uchar i;IIC_Start();//PCF8591地址定义1001****,高四位固定1001//第3,2,1位对应A2,A1,A0第0位为读写标志位,1为读0为写//下面代码中0x90,0x91分别为10010000,10010001 IIC_SendByte(0x90);if(IIC_ERROR == 1) return;IIC_SendByte(CtrlByte);if(IIC_ERROR == 1) return;IIC_Start();IIC_SendByte(0x91);if(IIC_ERROR == 1) return;IIC_ReceiveByte();Slave_ACK();for(i=0;i<4;i++){Recv_Buffer[i] = IIC_ReceiveByte();Slave_ACK();}Slave_NOACK();IIC_Stop();}void DAC_PCF8591(uchar CtrlByte,uchar dat){IIC_Start();Delay4us();IIC_SendByte(0x90);//发送地址字节if(IIC_ERROR == 1) return;IIC_SendByte(CtrlByte);//发送控制字节if(IIC_ERROR == 1) return;IIC_SendByte(dat);//发送待转换为模拟量的数值if(IIC_ERROR == 1) return;IIC_Stop();Delay4us();Delay4us();}/*PCF8591控制字节定义:0***0***,第3,7位固定为0 第6位取0时为模拟输入,取1时为模拟输出第4,5位为00表示4路单端的模拟输入第二位为自动递增标志,取1时自动递增第0,1位取值为00,01,10,11分别表示通道0,1,2,3 调用ADC_PCF8591时参数为00000100,即0x04调用DAC_PCF8591时参数为01000000,即0x40*/void main(){LCD_Initialise();while(1){ADC_PCF8591(0x04);Convert_To_V oltage(Recv_Buffer[0]);LCD_Line_1[2]=V oltage[2];LCD_Line_1[4]=V oltage[1];LCD_Line_1[5]=V oltage[0];Convert_To_V oltage(Recv_Buffer[1]);LCD_Line_1[10]=V oltage[2];LCD_Line_1[12]=V oltage[1];LCD_Line_1[13]=V oltage[0];Convert_To_V oltage(Recv_Buffer[2]);LCD_Line_2[2]=V oltage[2];LCD_Line_2[4]=V oltage[1];LCD_Line_2[5]=V oltage[0];Convert_To_V oltage(Recv_Buffer[3]);LCD_Line_2[10]=V oltage[2];LCD_Line_2[12]=V oltage[1];LCD_Line_2[13]=V oltage[0];LCD_Display_A_Line(0x00, LCD_Line_1);LCD_Display_A_Line(0x40, LCD_Line_2);DAC_PCF8591(0x40,Recv_Buffer[0]);}}。
PCF8591AD与DA转换器

广州周立功单片机发展有限公司
PCF8951
8 位 A/D 与 D/A 转换器
1. 概述
PCF8591 是一款单电源、低功耗 8 位 COMS 型 A/D、D/A 转换芯片,它具有 4 路模拟 量输入通道、一路模拟量输出通道和 1 个 I2C 总线接口。该器件 I2C 从地址的低三位由芯片 的 A0、A1 和 A2 三个地址引脚决定,所以在不增加任何硬件的情况下同一条 I2C 总线最多 可以连接 8 个同类型的器件。
杭州周立功
地址:杭州市天目山路 217 号江南电子大厦 502 室 电话:(0571) 28139611 28139612 28139613
28139615 28139616 28139618 传真:(0571) 28139621
成都周立功
地址:成都市一环路南二段 1 号数码同人港 401 室(磨 子桥立交西北角) 电话:(028)85439836 85437446 传真:(028)85437896
引脚号 6 7 8 9 10 11 12 13 14 15 16
PCF8951
8 位 A/D 与 D/A 转换器
描述
地址引脚
地 I2C 总线数据输入输出
I2C 总线时钟输入 时钟输入/输出
外部/内部时钟切换 模拟地
参考电压输入 D/A 转化模拟量输出
电源
续上表
产品简介手册
©2008 Guangzhou ZHIYUAN Electronics CO., LTD. 3
PCF8951
8 位 A/D 与 D/A 转换器
销售与服务网络(一)
广州周立功单片机发展有限公司
地址:广州市天河北路 689 号光大银行大厦 12 楼 F4 邮编:510630 电话:(020)38730916 38730917 38730972 38730976 38730977 传真:(020)38730925 网址:
PCF8591的介绍

//发送显示坐标
例子原理图及程序
LcdWriteCom(0x86); LcdWriteData('0'+adNum[1]/1000); LcdWriteData('0'+adNum[1]%1000/100); LcdWriteData('0'+adNum[1]%100/10); LcdWriteData('0'+adNum[1]%10); Pcf8591SendByte(3); //发送外部输入电压转换命令 adNum[2]=Pcf8591ReadByte()*2; //ADC2读取光敏
• PCF8591发送一次转换的程序 /************************************************************ * 函数名 : Pcf8591DaConversion * 函数功能 : PCF8591的输出端输出模拟量 * 输入 : value(转换的数值) * 输出 :无 ******************* *****************************************/ void Pcf8591DaConversion(unsigned char value) { I2cStart(); I2cSendByte(WRITEADDR);//发送写器件地址 I2cSendByte(0x40);//开启DA写到控制寄存器 I2cSendByte(value);//发送转换数值 I2cStop(); }
PCF8591介绍
控制字: 发送到 PCF8591 的第二个字节将被存储在控制寄存器,用于控制 器件功能。控制寄存器的高半字节用于允许模拟输出,和将模拟输 入编程为单端或差分输入。低半字节选择一个由高半字节定义的模 拟输入通道。如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加。
请问各位为什么下面的I2C总线程序(AD转换)需要空读一次芯片PCF8591

请问各位为什么下面的I2C总线程序(A/D转换)需要空读一次:芯片:PCF85912011-5-9 11:23提问者:xyzhong163|浏览次数:451次//-------------------------------------------------------------------// 函数名称:ADC_PCF8591// 入口参数:controlbyte控制字// 函数功能:连续读入4路通道的A/D转换结果到receivebuf//-------------------------------------------------------------------void ADC_PCF8591(uchar controlbyte){uchar idata receive_da,i=0;iic_start();IICSendByte(PCF8591_WRITE); //控制字1001 000 0check_ACK();if(askflag == 1){SystemError = 1;return;}IICSendByte(controlbyte); //控制字check_ACK();if(askflag == 1){SystemError = 1;return;}iic_start(); //重新发送开始命令IICSendByte(PCF8591_READ); //控制字1001 000 1check_ACK();if(askflag == 1){SystemError = 1;return;}IICreceiveByte(); //空读一次,调整读顺序slave_ACK(); //收到一个字节后发送一个应答位while(i<4){receive_da=IICreceiveByte();receivebuf[i++]=receive_da;slave_ACK(); //收到一个字节后发送一个应答位}slave_NOACK(); //收到最后一个字节后发送一个非应答位iic_stop();}我来帮他解答2011-5-9 19:52满意回答因为第一次读到的数据是上次转换的数据,要想得到这一次的数据需要第二次读取提问者对回答的评价:谢谢您的回复!!!我觉得主要是因为自动增量模式的下一个读取通道一定是通道0,。
信号发生器单片机程序PCF8591
/*置时钟线为高使数据线上数据有效*/
_Nop();
_Nop();
retc=retc<<1;
读数据位 接收的数据位放入 中 if(SDA==1)retc=retc+1; /*
,
retc */
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/********************************************************************
信号发生器程序信号发生器程序信号发生器程序信号发生器程序includereg52hincludeincludeunsignedcharcodesin1001280013597143921518015958167251747518918196052026520895214942205822586230752352323929242912460824878251012527525400254752550025475254002527525101248782429123929235232307522586220582149420895202651960518918182071747516725159581518014392135971280012003112081042096428875812573936682599553354705410635423014252520771671130999272249932520012510012520032549972299213091671207725253014354241064705533559956682739381258875964210420112081200312800sbitp14p14
PCF8591
PCF8591是8bit的A/D和D/A芯片,采用i2c接口,它有四路模拟输入口和一个模拟输出口,采样速率取决于i2c的速率。
数据传输是高位在前低位在后(不论是主机写入数据,还是主机读取的数据)。
写入数据时:起始信号->器件地址->应答信号->控制字节->写入的数据->应答信号(从机)->写入的数据->应答信号(从机)。
->停止信号读取数据时:起始信号->器件地址(写)->应答信号(从机)->控制字节->应答信号(从机)->停止信号(这个前提是设置读取的是哪一个通道,采用的哪种模式) 接着再是:起始信号->器件地址(读)->读取的字节->非应答信号(主机)->停止信号下图是AD通道自动增量模式采集数据时的数据格式:具体指令格式请参考PCF8591的数据手册。
下面是PCF8591的模拟输出和模拟输入的程序:/**************************************************************************Describe:PCF85891数模和模数转换** Time: 2015.5.20** Author: zys*************************************************************************/#include <reg52.h>#include <intrins.h>sbit SCL = P1^5;sbit SDA = P3^6;#define ADONE 0.0198 //5.06/256V PCF8591的Vref电压是5.06V/***本程序数码管是共阴极的***/const unsigned char smg_dp_yin[ 16 ] = {0xbf, 0x86, 0xdb, 0xcf, 0xe6, 0xed, 0xfd, 0x87, 0xff, 0xef,0xf7, 0xfc, 0xb9, 0xde, 0xfb, 0xf1};//0. 1. 2. 3......f.//共阴极,显示小数点//不显示小数点: smg_dp_yin[x] & 0x7f//共阳极显示小数点:~smg_dp_yin[x]//共阳极不显示小数点:~(smg_dp_yin[x] | 0x80)/****数码管的位是通过74LS138控制的****/const unsigned char smg_8_pos[ 8 ] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; //对应P20,P21,P22,高位都为1,则与的时候P2的其他位不变const unsigned char smg_sum = 8; //8位数码管void i2c_start( void );void i2c_stop( void );void i2c_ack( void );void master_ack();void master_notAck();void i2c_writeByte( unsigned char byte);unsigned char i2c_readByte( void );void PCF8591_wirteCommand( unsigned char addr, unsigned char command ); void PCF8591_AOUT(unsigned char byte);unsigned char i2c_readADResult( void );void PCF8591_displayADResult( unsigned int ADResult);void delay( void );void i2c_delay( void );void delay_xms(unsigned int );/********************************************************** 函数名: void main( void )**输入参数:无**返回参数:无********************************************************/void main( void ){int i = 0;int ch = 0;while(1){/*for(i = 0; i <= 255; i++) //DA输出,呼吸灯效果{PCF8591_AOUT(i);delay();}for(i = 255; i >= 0; i--){PCF8591_AOUT(i);delay();} */for(ch = 0; ch < 4; ch++) //循环采集四路电压{PCF8591_wirteCommand(0x90, 0x00+ch);for(i = 0; i < 1000; i++){PCF8591_displayADResult(i2c_readADResult());}}}}/******************************************************** ** 函数名: void i2c_start( void ),i2c起始信号**输入参数:无**返回参数:无********************************************************/ void i2c_start( void ){SCL = 1;SDA = 1;i2c_delay();SDA = 0;i2c_delay();SCL = 0;i2c_delay();}/******************************************************** ** 函数名: void i2c_stop( void ),i2c停止信号**输入参数:无**返回参数:无********************************************************/ void i2c_stop( void ){SDA = 0;i2c_delay();SCL = 1;i2c_delay();SDA = 1;i2c_delay();}/******************************************************** ** 函数名: void i2c_ack( void ),i2c应答信号(从机)**输入参数:无**返回参数:无********************************************************/ void i2c_ack( void ){int i = 0;SCL = 0;i2c_delay();SDA = 1;i2c_delay();SCL = 1;i2c_delay();while(SDA == 1);/*while((SDA == 1) && ((i++) < 10)){_nop_();}*/}/********************************************************** 函数名: void master_ack( void ),主机应答信号,在读取数据时**输入参数:无**返回参数:无********************************************************/ void master_ack( void ){SCL = 0;i2c_delay();SDA = 0;i2c_delay();SCL = 1;i2c_delay();SCL = 0;i2c_delay();SDA = 1;i2c_delay();}/********************************************************** 函数名: void master_notAck( void ),主机非应答信号,在读取数据时**输入参数:无**返回参数:无********************************************************/ void master_notAck( void ){SCL = 0;i2c_delay();SDA = 1;i2c_delay();SCL = 1;i2c_delay(); // 没下面四句程序读取不正常SCL = 0; //i2c_delay(); //SDA = 0; //}/******************************************************** ** 函数名: void i2c_writeByte,i2c写一个字节**输入参数:unsigned char byte**返回参数:无********************************************************/ void i2c_writeByte( unsigned char byte ){char loop;for(loop = 0; loop < 8; loop++){SCL = 0;i2c_delay();if((byte<<loop)&0x80) //数据是从高位到低位传输{SDA = 1;}else{SDA = 0;}i2c_delay();SCL = 1;i2c_delay();}}unsigned char i2c_readByte( void ){int loop = 0;unsigned char temp = 0;unsigned char tempData = 0;//SDA = 0;for(loop = 7; loop >= 0; loop--){SCL = 0;i2c_delay();temp = SDA;i2c_delay();i2c_delay();tempData += (temp<<loop);temp = 0;}return tempData;}/********************************************************** 函数名: void PCF8591_wirteCommand( unsigned char addr, unsigned char command ),PCF8591写控制指令**输入参数:unsigned char addr, unsigned char command**返回参数:无********************************************************/void PCF8591_wirteCommand( unsigned char addr, unsigned char command ){i2c_start();i2c_writeByte(addr);i2c_ack();i2c_writeByte(command);i2c_ack();i2c_delay();i2c_stop();}/********************************************************** 函数名: unsigned char i2c_readADResult( void ),i2c读出一个字节**输入参数:无**返回参数:unsigned char********************************************************/unsigned char i2c_readADResult( void ){unsigned char temp = 0;i2c_start();i2c_writeByte(0x91);i2c_ack();temp = i2c_readByte();master_notAck();i2c_stop();return temp;}/********************************************************** 函数名: void PCF8591_displayADResult( unsigned int ADResult),显示AD采集的数据**输入参数:unsigned int ADResult********************************************************/void PCF8591_displayADResult( unsigned int ADResult){char loop = 0;unsigned int temp = ADONE * ADResult * 100; //两位小数取出来unsigned int dec = 1;for(loop = 7; loop >= 5; loop--){if(loop == 5){P0 = smg_dp_yin[temp/dec%10];}else{P0 = smg_dp_yin[temp/dec%10]&0x7f;}P2 = smg_8_pos[loop];delay_xms(1);dec *= 10;}}/********************************************************** 函数名: void PCF8591_AOUT( unsigned char byte ),DA输出**输入参数:unsigned char byte**返回参数:无********************************************************/void PCF8591_AOUT( unsigned char byte ){i2c_start();i2c_writeByte(0x90);i2c_ack();i2c_writeByte(0x40); //只有模拟输出AOUTi2c_ack();i2c_writeByte(byte);i2c_ack();i2c_stop();}/************************************************************************ **函数名:void i2c_delay( void ),i2c专用延时** 功能:无*************************************************************************/ void i2c_delay( void ){char loop;for(loop = 0; loop < 5; loop++){_nop_();}}/************************************************************************ **函数名:void delay_xms( unsigned int x )** 功能:延时xms** 参数: 无*************************************************************************/ void delay_xms( unsigned int x ){unsigned char j = 0;while( x-- ){while( (j++) < 100 );j = 0;}}/************************************************************************ **函数名:void delay( void ),在输出DA数据时使用的延时** 功能:无** 参数: 无*************************************************************************/ void delay( void ){unsigned int loop;for(loop = 0; loop < 30; loop++){_nop_();}}。
PCF8591详解
PCF8591详解PCF8591应⽤程序<上⼀节下⼀节>分享到:QQ空间新浪微博腾讯微博⾖瓣⼈⼈⽹在线学习编程开发,零基础到精通教程任你挑:北风⽹PCF8591 的通信接⼝是I2C,那么编程肯定是要符合这个协议的。
单⽚机对PCF8591 进⾏初始化,⼀共发送三个字节即可。
第⼀个字节,和EEPROM 类似,是器件地址字节,其中7 位代表地址,1 位代表读写⽅向。
地址⾼4 位固定是0b1001,低三位是A2,A1,A0,这三位我们电路上都接了GND,因此也就是0b000,如图17-5 所⽰。
图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 模拟输出的电压值。
pcf8591c语言程序附加注释
#include<reg52.h>#include <I2C.H>#define PCF8591 0x90 //PCF8591 地址sbit LS138A=P2^2;sbit LS138B=P2^3;sbit LS138C=P2^4;sbit SD=P2^0; //设定功能键sbit JY=P2^1; //加一sbit JYY=P2^2; //减一sbit BC=P2^3; //保存/退出sbit JDQ=P1^0; //继电器输出unsigned char code Disp_Tab[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //此表为LED 的字模, 共阴数码管0-9 -unsigned char AD_CHANNEL;unsigned long xdata LedOut[8];unsigned int D[32];unsigned char GNSZ(unsigned int);void delay(char j);unsigned int GL;/*******************************************************************DAC 变换, 转化函数*******************************************************************/bit DACconversion(unsigned char sla,unsigned char c, unsigned char Val){Start_I2c(); //启动总线SendByte(sla); //发送器件地址if(ack==0)return(0);SendByte(c); //发送控制字节if(ack==0)return(0);SendByte(Val); //发送DAC的数值if(ack==0)return(0);Stop_I2c(); //结束总线return(1);}/*******************************************************************ADC发送字节[命令]数据函数*******************************************************************/bit ISendByte(unsigned char sla,unsigned char c){Start_I2c(); //启动总线SendByte(sla); //发送器件地址if(ack==0)return(0);SendByte(c); //发送数据if(ack==0)return(0);Stop_I2c(); //结束总线return(1);}/******************************************************************* ADC读字节数据函数*******************************************************************/ unsigned char IRcvByte(unsigned char sla){ unsigned char c;Start_I2c(); //启动总线SendByte(sla+1); //发送器件地址if(ack==0)return(0);c=RcvByte(); //读取数据0Ack_I2c(1); //发送非就答位Stop_I2c(); //结束总线return(c);}//******************************************************************/ main(){ char i,j;while(1){/***********以下是功能选择*********/if(SD==1)delay(20);if(SD==1)P0=0;GL=GNSZ(GL);/********以下AD-DA处理*************/switch(AD_CHANNEL){case 0: ISendByte(PCF8591,0x41);D[1]=IRcvByte(PCF8591); //ADC0 模数转换1 放大2倍显示break;}if(++AD_CHANNEL>4) AD_CHANNEL=0;if(D[1]>GL)JDQ=0;elseJDQ=1;/********以下将AD的值送到LED数码管显示*************/LedOut[0]=Disp_Tab[D[1]%10000/1000];LedOut[1]=Disp_Tab[D[1]%1000/100];LedOut[2]=Disp_Tab[D[1]%100/10]|0x80;LedOut[3]=Disp_Tab[D[1]%10];for( i=0; i<4; i++){ P0 = LedOut[i];switch(i) //使用switch 语句控制138译码器也可以是用查表的方式学员可以试着自己修改{case 0:LS138A=0; LS138B=0; LS138C=0; break;case 1:LS138A=1; LS138B=0; LS138C=0; break;case 2:LS138A=0; LS138B=1; LS138C=0; break;case 3:LS138A=1; LS138B=1; LS138C=0; break;}for (j = 0 ; j<90 ;j++) { ;} //扫描间隔时间}P0 = 0;}}/**************功能选择函数***************/unsigned char GNSZ(unsigned int GL){char i,j;while(1){if(JY==1)delay(20);if(JY==1)GL=GL+1;if(JYY==1)delay(20);if(JYY==1)GL=GL-1;LedOut[0]=Disp_Tab[GL%10000/1000];LedOut[1]=Disp_Tab[GL%1000/100];LedOut[2]=Disp_Tab[GL%100/10]|0x80;LedOut[3]=Disp_Tab[GL%10];for( i=0; i<4; i++){ P0 = LedOut[i];switch(i) //使用switch 语句控制138译码器也可以是用查表的方式学员可以试着自己修改{case 0:LS138A=0; LS138B=0; LS138C=0; break;case 1:LS138A=1; LS138B=0; LS138C=0; break;case 2:LS138A=0; LS138B=1; LS138C=0; break;case 3:LS138A=1; LS138B=1; LS138C=0; break;}for (j = 0 ; j<90 ;j++) { ;} //扫描间隔时间}P0 = 0;if(BC==1)delay(20);if(BC==1)return(GL);}}void delay(char j){char n,m;for(n=0;n<j;n++){for(m=0;m<120;m++){;}} }。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
PCF8591读写程序 (一)、PCF8591
1、引脚说明 ANI0~ANI3 为模拟信号输入端,不使用的输入端应接地 A0~A2 地址输入端 GND、VCC 地和电源端(+5V) SDA 为I2C数据输入与输出端 SCL 为I2C时钟输入端 EXT 内外部时钟选择端,使用内部时钟时接地,使用外部时钟时接+5V OSC 外部时钟输入、内部时钟输出端,不使用时应悬空 AGND 模拟信号地 VREF 基准电压输入端 AOUT D/A转换后的电压输出端 2、功能说明 PCF8591是具有I2C总线接口的8位A/D及D/A转换器,具有4路A/D输入,1路D/A输出。PCF8591采用典型的I2C总线接口器件寻址方法,即总线地址由器件地址(1001)、引脚地址(由A0~A2接地或+5V来确定,接地代表0;接+5V代表1)、方向位(即R/W)组成。因此,在I2C总线系统中最多可接8个这样的器件。
D7 D6 D5 D4 D3 D2 D1 D0 1 0 0 1 A2 A1 A0 R/W
R/W=1表示读操作,R/W=0表示写操作。本例将A0~A2接地,则读地址为91H;写地址为90H。 地址字节:由器件地址、引脚地址、方向位组成,它是通信时主机发送的第一字节数据。 控制字节:用于控制PCF8951的输入方式、输入通道、D/A转换等,是通信时主机发送的第二字节数据,其格式如下: D7 D6 D5 D4 D3 D2 D1 D0 未用 (写0) D/A输出允许位 0为禁止 1为允许 A/D输入方式选择位00:4路单端输入 01:3路差分输入 10:单端与差分 11:2路差分输入 未用 (写0) 自动增益选择位 0为禁用 1为启用
AD通道选择位 00:选择通道0 01:选择通道1 10:选择通道2 11:选择通道3
A/D输入方式选择说明:
3、通信格式 第一字节 第二字节 第三字节
写入器件地址(90H) 写入控制字节 要写入的数据 向PCF8591写入格式(高位在前)
第一字节 第二字节 第三字节 第四字节 写入器件地址(90H写) 写入控制字节 写入器件地址(91H读) 读出一字节数据 从PCF8591读数据格式(高位在前) (二)、I2C总线 1、I2C总线数据位的传输 它通过2根线:串行数据线(SDA)和串行时钟线(SCL)组成。连接到总线上的每一个器件都有一个唯一的地址,而且都可以作为一个发生器或接收器,SDA和SCL都是双向线路,分别通过一个电阻连接到电源(+5V)端。前提是连接到总线上的器件的SDA和SCL端必须是漏极或集电极开路型。I2C总线上的数据传输速率在标准模式下可达100Kb/s,快速模式可达400Kb/s,高速模式下可达s。连接到总线的器件数量只由总线的电容(400PF)限制决定。 I2C总线上每传输一个数据位必须产生一个时钟脉冲,I2C总线上数据传输的有效性要求SDA线上的数据必须在时钟线SCL的高电平期间保存稳定,数据线的改变只能在时钟线为低电平期间。在标准模式下,高低电平宽度必须大于(即每次时钟线需延时后才能改变)。 2、I2C总线数据的传输 数据传输的字节格式 发送到SDA线上的每一个字节必须为8位,每次发送的字节数量不受限制,从机在接收完一个字节后向主机发送一个应答位,主机在收到从机应答后才会发送第二字节数据,发送数据时先发数据的最高位。 数据传输中的应答 相应的应答位由接收方(从机)产生,在应答的时钟脉冲期间,发送方(主机)应释放SDA线(使其为高电平)。在应答过程中,接收方(从机)必须将数据线SDA拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。 3、I2C总线的传输协议 寻址字节 主机产生起始条件后,发送的第一字节为寻址字节,该字节的前7位为从机地址,最低位决定了传输的方向,该最低位为“0”表示主机写数据到从机,“1”表示主机从从机中读数据。从机地址由一个固定的部分(如高4位1001)和可编程部分(如低3位A0~A2)及一个方向位(R/W)组成。 传输格式 主机产生起始条件后,首先发送一个寻址字节,收到从机应答后,接着就传输数据,数据传输一般由主机产生的停止位终止。但如果主机仍希望在总线上通信,则它可以产生重复起始条件和寻址另一个从机,而不必产生一个停止条件。 主机写数据到从机的通信格式如下:
1 2 3 4 5 6 7 N N-1 主机产生起始位 发从机地址90H 等待从机应答 发送数据 等待从机应答 发送数据 等待从机应答 。。。。 停止位
主机从从机中读数据的通信格式如下: 1 2 3 4 5 6 7 N N-1 主机产生起始位 发从机地址91H 等待从机应答 接收从机发出的数据 向从机应答 接收从机发出的数据 向从机应答 。。。。 主机产生停止位
原理图如下: 汇编源代码如下: ;//本测试程序将AIN0通道的模拟电压进行A/D转换后,将数字量通过LED数码管显示出来,同时再将该数字 ;//量写入PCF8591中,通过其内部的D/A转换为模拟电压输出驱动LED发光二极管。 ACK BIT ;应答标志位ACK=0表示无应答 SCL BIT ;时钟线 SDA BIT ;数据线 WADD EQU 21H ;器件地址(即从地址) SUBD EQU 22H ;器件内部地址(即子地址) NUMBR EQU 23H ;需读取的字节数 NUMBW EQU 24H ;需写入的字节数 RDATA EQU 25H ;读出数据的存放首地址 WDATA EQU 26H ;写入数据的存放首地址
ORG 0000H SJMP MAIN ORG 0030H MAIN: MOV WADD,#90H ;写入PCF8591的地址 MOV P0,#0FFH ;关闭显示 MOV P2,#0FFH MOV SUBD,#40H ;写入PCF8591的控制字 MOV NUMBR,#1 ;写入需读取的字节数 MOV NUMBW,#1 ;写入需写入的字节数 MOV RDATA,#30H ;送入首地址 MOV WDATA,#40H ;送入首地址 MOV 50H,#0 ;显示的百位清零 MOV 51H,#0 ;显示的十位清零 MOV 52H,#0 ;显示的个位清零 M1: LCALL READI2C ;读PCF8591子程序 MOV 40H,30H MOV NUMBR,#1 MOV NUMBW,#1 LCALL DAT LCALL DISPLAY LCALL WRITEI2C ;写PCF8591子程序 SJMP M1
;数据处理子程序 DAT: MOV A,30H MOV B,#100 DIV AB MOV 50H,A MOV A,#10 XCH A,B DIV AB MOV 51H,A MOV 52H,B RET
;显示子程序 DISPLAY: MOV DPTR,#TAB MOV A,50H MOVC A,@A+DPTR MOV P0,A MOV P2,#01H LCALL TIM2MS MOV A,51H MOVC A,@A+DPTR MOV P0,A MOV P2,#02H LCALL TIM2MS MOV A,52H MOVC A,@A+DPTR MOV P0,A MOV P2,#04H LCALL TIM2MS RET ;2ms延时子程序 TIM2MS: MOV R6,#2 TIM1: MOV R5,#250 TIM2: NOP NOP DJNZ R5,TIM2 DJNZ R6,TIM1 RET
TAB: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,0BFH,8CH,0C6H,0C7H,86H,0FFH ;共阳数码管 ;从I2C总线读取N个字节数据子程序 READI2C: LCALL STARTI2C ;启动I2C总线 MOV A,WADD ;送入器件地址 LCALL WI2C ;向I2C总线发送一个字节数据子程序 LCALL RACK ;读取从机应答位子程序 JNB ACK,ROUT ;判断从机有无应答ACK=0则无应答 MOV A,SUBD ;送入器件内部地址 LCALL WI2C LCALL RACK LCALL STARTI2C MOV A,WADD INC A ;改总线为读取状态 LCALL WI2C LCALL RACK JNB ACK,READI2C MOV R0,RDATA ;送入读出数据的存放首地址 RI2C2: LCALL RI2C MOV @R0,A DJNZ NUMBR,RI2C1 ;判断字节读取完否 LCALL NMACK ;调主机非应答子程序 ROUT: LCALL STOPI2C ;调I2C总线停止子程序 MOV RDATA,#30H RET RI2C1: LCALL MACK ;调主机应答子程序 INC R0 SJMP RI2C2
;向I2C总线发送N个字节数据子程序 WRITEI2C: LCALL STARTI2C ;启动I2C总线 MOV A,WADD ;送入器件地址 LCALL WI2C ;向I2C总线发送一个字节数据子程序