#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define PCF8591ADDR 0X90 //PCF8591硬體地址
#define I2cRead 1 //I2C讀方向位
#define I2cWrite 0 //I2C寫方向位
#define CH0 0 //AD通道0
#define CH1 1 //AD通道1
#define CH2 2 //AD通道2
#define CH3 3 //AD通道3
#define DAout 0x40 //DA輸出命令
sbit DU = P2^6;//數碼管段選
sbit WE = P2^7;//數碼管段選
sbit SCL = P2^1; //I2C時鐘總線
sbit SDA = P2^0; //I2C資料總線
uchar num;//數碼管顯示的值
bit AckFlag;//應答標志位
//共陰數碼管段選表0-9
uchar code SMGduan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
//數碼管位選碼
uchar code SMGwei[] = {0xfe, 0xfd, 0xfb};
/*====================================
函式 : delay(uint z)
引數 :z 延時毫秒設定,取值范圍0-65535
回傳值 :無
描述 :12T/Fosc11.0592M毫秒級延時
====================================*/
void delay(uint z)
{
uint x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
/*====================================
函式 :display(uchar i)
引數 :i 顯示數值,取值范圍0-255
回傳值 :無
描述 :三位共陰數碼管動態顯示
====================================*/
void display(uchar i)
{
static uchar wei;
P0 = 0XFF;//清除斷碼
WE = 1;//打開位選鎖存器
P0 = SMGwei[wei];
WE = 0;//鎖存位選資料
switch(wei)
{
case 0: DU = 1; P0 = SMGduan[i / 100]; DU = 0; break;
case 1: DU = 1; P0 = SMGduan[i % 100 / 10]; DU = 0; break;
case 2: DU = 1; P0 = SMGduan[i % 10]; DU = 0; break;
}
wei++;
if(wei == 3)
wei = 0;
}
//定時器0初始化
void timer0Init()
{
EA = 1; //打開總中斷
ET0 = 1;//打開定時器0中斷
TR0 = 1; //啟動定時器0
TMOD |= 0X01; //定時器作業模式1,16位定時模式
TH0 = 0xED;
TL0 = 0xFF; //定時5ms
}
/****************************************************
IIC通信代碼
****************************************************/
/*====================================
函式 :delay5us()
引數 :無
回傳值 :無
描述 :5us延時函式
====================================*/
void delay5us()
{
_nop_();
}
/*====================================
函式 :I2cStart()
引數 :無
回傳值 :無
描述 :I2C總線起始信號
====================================*/
void I2cStart()
{
//時鐘總線為高電平期間資料總線又高變低產生起始型號
SCL = 1;
SDA = 1;
delay5us();//狀態保持5us
SDA = 0;
delay5us();//狀態保持5us
}
/*====================================
函式 :I2cStop()
引數 :無
回傳值 :無
描述 :I2C總線停止信號
====================================*/
void I2cStop()
{
//時鐘總線為高電平期間,資料總線從高變低產生終止信號
SCL = 0;
SDA = 0;
SCL = 1;
delay5us();//狀態保持5us
SDA = 1;
delay5us();//狀態保持5us
}
/*====================================
函式 :ReadACK()
引數 :無
回傳值 :1非應答,0應答
描述 :I2C總線讀從機應答信號
====================================*/
bit ReadACK()
{
SCL = 0;//拉低時鐘總線,允許從機控制SDA
SCL = 1;//拉高,讀SDA
delay5us();
if(SDA)//NOACK
{
SCL = 0;
return(1);//回傳1
}
else//ACK
{
SCL = 0;
return(0);//回傳0
}
}
/*====================================
函式 :SendACK(bit i)
引數 :1主機發送非應答,0發送應答
回傳值 :無
描述 :主機發送應答信號
====================================*/
void SendACK(bit i)
{
SCL = 0;//拉低時鐘總線,允許主機控制SDA
if(i) //發非應答
SDA = 1;
else //發應答
SDA = 0;
SCL = 1; //拉高總線,讓從機讀SDA
delay5us();//保持5us
SCL = 0; //拉低時鐘總線,允許SDA釋放
SDA = 1;//釋放資料總線
}
/*====================================
函式 :I2cSendByte(uchar DAT)
引數 :DAT需要發送的資料
回傳值 :無
描述 :I2C發送一個位元組資料
====================================*/
void I2cSendByte(uchar DAT)
{
uchar i;
for(i=0; i<8; i++) //分別寫8次,每次寫1位
{
SCL = 0;//拉低時鐘總線,允許SDA變化
if(DAT & 0x80)//先寫資料最高位
SDA = 1; //寫1
else
SDA = 0; //寫0
SCL = 1; //拉高時鐘,讓從機讀SDA
DAT <<= 1; //為發送下一位左移1位
}
SCL = 0; //拉低時鐘總線,允許SDA釋放
SDA = 1;//釋放資料總線
}
/*====================================
函式 :Pcf8591DA(uchar Ctrl, DAT)
引數 :Ctrl 8591控制位元組,DAT 要寫入的資料
回傳值 :無
描述 :PCF8591數字量轉模擬量輸出
====================================*/
void Pcf8591DA(uchar Ctrl, DAT)
{
I2cStart();//I2C起始信號
I2cSendByte(PCF8591ADDR + I2cWrite);//發送器件地址加讀寫方向位
if(ReadACK()) //讀從機應答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(Ctrl);//發送控制位元組
if(ReadACK())//讀從機應答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(DAT);//發送一位元組資料
if(ReadACK())//讀從機應答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cStop(); //I2C停止信號
}
/*====================================
函式 :I2cReadByte()
引數 :無
回傳值 :回傳讀出的一位元組資料
描述 :I2C總線讀一位元組資料
====================================*/
uchar I2cReadByte()
{
uchar i, DAT;
for(i=0; i<8; i++)//分別讀8次,每次讀一位
{
DAT <<= 1; //資料左移1位,準備接收一位
SCL = 0; //拉低時鐘總線,允許從機控制SDA變化
SCL = 1; //拉高時鐘總線,讀取SDA上的資料
if(SDA)
DAT |= 0X01;//為1則寫1,否則不行執行寫1,通過左移補0
}
return(DAT); //回傳讀出的資料
}
/*====================================
函式 :PCF8591Read(uchar Ctrl)
引數 :Ctrl 8591控制位元組
回傳值 :AD轉出的數字量
描述 :讀指定通道的輸入的模擬量專為數字量
====================================*/
uchar PCF8591Read(uchar Ctrl)
{
uchar DAT;
I2cStart();//I2C起始信號
I2cSendByte(PCF8591ADDR + I2cWrite);//發送器件地址加讀寫方向位
if(ReadACK())//讀從機應答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
I2cSendByte(Ctrl);//發送控制位元組
ReadACK();//讀從機應答
I2cStart();//再次產生I2C起始信號
I2cSendByte(PCF8591ADDR + I2cRead);//發送器件地址加讀寫方向位 讀
if(ReadACK())//讀從機應答
AckFlag = 1; //NOACK
else
AckFlag = 0; //ACK
DAT = I2cReadByte();//讀一位元組
SendACK(1);//主機發送非應答
I2cStop(); //I2C停止信號
return(DAT);//回傳讀出資料
}
void main()//main函式自身會回圈
{
timer0Init();//定時器0初始化
while(1)
{
EA = 0;//屏蔽中斷
num = PCF8591Read(0);//讀AD通道0,光敏值
Pcf8591DA(DAout, num);//把光敏轉出的數字量取反,輸出模擬量控制LED10
EA = 1;//開中斷
delay(5);
}
}
//定時器0中斷函式
void timer0() interrupt 1
{
TH0 = 0xED;
TL0 = 0xFF; //定時5ms
display(num); //數碼管顯示函式
}
uj5u.com熱心網友回復:
很明顯,數碼管顯示255,說明IIC根本沒讀到資料,最簡單的方法在控制電平時都加個延時uj5u.com熱心網友回復:
如果 I2C 驅動沒有問題的話,外設是否正常,并且會變化。可用示波器,邏輯分析儀等監視 I2C 引腳。另外
EA = 1; //打開總中斷這個初始化順序,改一下
ET0 = 1;//打開定時器0中斷
TR0 = 1; //啟動定時器0
TMOD |= 0X01; //定時器作業模式1,16位定時模式
TH0 = 0xED;
TL0 = 0xFF; //定時5ms
TMOD |= 0X01; //定時器作業模式1,16位定時模式
TH0 = 0xED;
TL0 = 0xFF; //定時5ms
ET0 = 1;//打開定時器0中斷
TR0 = 1; //啟動定時器0
EA = 1; //打開總中斷
uj5u.com熱心網友回復:
謝謝





uj5u.com熱心網友回復:
謝謝




轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/9278.html
標籤:單片機/工控
下一篇:攝像頭驅動
