單片機源程序如下:
#include "STC12C5A60S2.h"//主控芯片的頭文件
/************************常用數據類型定義*************************/
#include <intrins.h>
/********************常用數據類型定義**********************/
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;
/*************************宏定義***************************/
//#define _Nop() _nop_() //定義空指令
#define PCA9698 0x40 //PCA9698地址
/*******************端口/引腳定義區域**********************/
sbit SDA=P3^7; //模擬I2C數據傳送位
sbit SCL=P3^6; //模擬I2C時鐘控制位
sbit BLUE=P4^6;
bit ack; //應答標志位
/*********************函數聲明區域*************************/
void Delay_MS(u16 Count); //毫秒延遲函數
void _Nop(); //定義空指令
void Start_I2c(void); //IIC起動總線函數
void Stop_I2c(void); //IIC結束總線函數
void SendByte(u8 c); //IIC字節發送函數
u8 RcvByte(void); //IIC字節接收函數
void Ack_I2c(bit a); //IIC應答函數
bit ISendByte(u8 sla,u8 c);//向無子地址器件發送字節數據函數
bit ISendStr(u8 sla,u8 suba,u8 *s,u8 no);
//向有子地址器件發送多字節數據函數
bit IRcvByte(u8 sla,u8 *c);//向無子地址器件讀字節數據函數
bit IRcvStr(u8 sla,u8 suba,u8 *s,u8 no);
//向有子地址器件接收多字節數據函數
//*********************主函數區域**************************/
void main(void)
{
u8 All_ctrl[1]={0x80};
//設置全組控制寄存器數組(這里為默認值)
u8 Select_Mode[1]={0x12};
//設置模式選擇寄存器(這里配置為應答時輸出改變 使能中斷響應)
u8 GPIO_H[1]={0xff};
//設置I/O端口狀態數組
u8 GPIO_L[1]={0x00};
//設置I/O端口狀態數組
//u8 In_array[1]={0x7f};
//設置I/O某端口號為中斷標志位
Delay_MS(10);
ISendStr(PCA9698,0X2A,Select_Mode,1);
//配置模式選擇寄存器地址0x2A
ISendStr(PCA9698,0X29,All_ctrl,1);
//配置全組控制寄存器地址0X29
ISendStr(PCA9698,0X28,GPIO_H,1);
//配置輸出結構寄存器地址0X28(寫入1為默認推挽,0為開漏),這里配置為推挽
//ISendStr(PCA9698,0X23,In_array,1);
//0X23為中斷屏蔽地址寄存器,配置為使用PD8作為中斷標志位
//當PD8端口狀態改變時中斷發生,中斷輸出引腳In變低電平
//配置I/0口寄存器(設置為輸出/輸入,A~D組地址為0X18~0X1C)
ISendStr(PCA9698,0X18,GPIO_L,1);//配置A組I/O為輸出
ISendStr(PCA9698,0X19,GPIO_L,1);//配置B組I/O為輸出
ISendStr(PCA9698,0X1A,GPIO_L,1);//配置C組I/O為輸出
ISendStr(PCA9698,0X1B,GPIO_L,1);//配置D組I/O為輸出
ISendStr(PCA9698,0X1C,GPIO_L,1);//配置E組I/O為輸出
while(1)
{
//配置輸出端口寄存器(設置輸出相應的狀態,A~E組端口的地址為0X08~0X0C)
Delay_MS(500);
ISendStr(PCA9698,0X08,GPIO_L,1);//A推挽輸出高電平
ISendStr(PCA9698,0X09,GPIO_L,1);//B推挽輸出高電平
ISendStr(PCA9698,0X0a,GPIO_L,1);//C推挽輸出高電平
ISendStr(PCA9698,0X0b,GPIO_L,1);//D推挽輸出高電平
ISendStr(PCA9698,0X0c,GPIO_L,1);//E推挽輸出高電平
Delay_MS(500);//延遲閃爍
ISendStr(PCA9698,0X08,GPIO_H,1);//A推挽輸出低電平
ISendStr(PCA9698,0X09,GPIO_H,1);//B推挽輸出低電平
ISendStr(PCA9698,0X0a,GPIO_H,1);//C推挽輸出低電平
ISendStr(PCA9698,0X0b,GPIO_H,1);//D推挽輸出低電平
ISendStr(PCA9698,0X0C,GPIO_H,1);//E推挽輸出低電平
}
}
//***************************************************************/
//起動總線函數Start_I2c(void),無形參,無返回值
//***************************************************************/
void Start_I2c(void)
{
SDA=1; //發送起始條件的數據信號
_Nop();
SCL=1;
_Nop(); //起始條件建立時間大于4.7us,延時
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; //發送起始信號
_Nop(); //起始條件鎖定時間大于4μs
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; //鉗住I2C總線,準備發送或接收數據
_Nop();
_Nop();
}
//***************************************************************/
//結束總線函數 Stop_I2c(void),無形參,無返回值
//***************************************************************/
void Stop_I2c(void)
{
SDA=0; //發送結束條件的數據信號
_Nop(); //發送結束條件的時鐘信號
SCL=1; //結束條件建立時間大于4μs
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; //發送I2C總線結束信號
_Nop();
_Nop();
_Nop();
_Nop();
}
//***************************************************************/
//IIC字節數據傳送函數SendByte(u8 c),有形參c,無返回值
//***************************************************************/
void SendByte(u8 c)
{
u8 BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++)
{
//要傳送的數據長度為8位
if((c<<BitCnt)&0x80)
SDA=1; //判斷發送位
else
SDA=0;
_Nop();
SCL=1; //置時鐘線為高,通知被控器開始接收數據位
_Nop();
_Nop(); //保證時鐘高電平周期大于4μs
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1; //8位發送完后釋放數據線,準備接收應答位
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)
ack=0;
else
ack=1; //判斷是否接收到應答信號
SCL=0;
_Nop();
_Nop();
}
//***************************************************************/
//IIC字節數據接收函數RcvByte(void),無形參,有返回值retc
//***************************************************************/
u8 RcvByte(void)
{
u8 retc;
u8 BitCnt;
retc=0;
SDA=1; //置數據線為輸入方式
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0; //置時鐘線為低,準備接收數據位
_Nop();
_Nop(); //時鐘低電平周期大于4.7μs
_Nop();
_Nop();
_Nop();
SCL=1; //置時鐘線為高使數據線上數據有效
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)
retc=retc+1; //讀數據位,接收的數據位放入retc中
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
//***************************************************************/
//IIC應答子函數Ack_I2c(bit a),有形參a,無返回值
//***************************************************************/
void Ack_I2c(bit a)
{
if(a==0)
SDA=0; //在此發出應答或非應答信號
else
SDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); //時鐘低電平周期大于4μs
_Nop();
_Nop();
_Nop();
SCL=0; //清時鐘線,鉗住I2C總線以便繼續接收*/
_Nop();
_Nop();
}
//***************************************************************/
//向無子地址器件發送字節數據函數 ISendByte(u8 sla,u8 c)
//有形參sla:地址;c:發送數據;無返回值
//***************************************************************/
bit ISendByte(u8 sla,u8 c)
{
Start_I2c(); //啟動總線
SendByte(sla); //發送器件地址
if(ack==0)
return(0);
SendByte(c); //發送數據
if(ack==0)
return(0);
Stop_I2c(); //結束總線
return(1);
}
//***************************************************************/
//向有子地址器件發送多字節數據函數ISendStr(u8 sla,u8 suba,u8 *s,u8 no)
//有形參sla:地址;suba:子地址;*s:數據數組;no:字節個數;有返回值1
//***************************************************************/
bit ISendStr(u8 sla,u8 suba,u8 *s,u8 no)
{
u8 i;
Start_I2c(); //啟動總線
SendByte(sla); //發送器件地址
if(ack==0)
return(0);
SendByte(suba); //發送器件子地址
if(ack==0)
return(0);
for(i=0;i<no;i++)
{
SendByte(*s); //發送數據
if(ack==0)return(0);
s++;
}
Stop_I2c(); //結束總線
return(1);
}
//***************************************************************/
//向無子地址器件讀字節數據函數IRcvByte(u8 sla,u8 *c)
//有形參sla:地址;suba:發送數據;*c:;有返回值1
//***************************************************************/
bit IRcvByte(u8 sla,u8 *c)
{
Start_I2c(); //啟動總線
SendByte(sla+1); //發送器件地址
if(ack==0)
return(0);
*c=RcvByte(); //讀取數據
Ack_I2c(1); //發送非就答位
Stop_I2c(); //結束總線
return(1);
}
//***************************************************************/
//向有子地址器件接收多字節數據函數IRcvStr(u8 sla,u8 suba,u8 *s,u8 no)
//有形參sla:地址;suba:子地址;*s:數據數組;no:字節個數;有返回值1
//***************************************************************/
bit IRcvStr(u8 sla,u8 suba,u8 *s,u8 no)
{
u8 i;
Start_I2c(); //啟動總線
SendByte(sla); //發送器件地址
if(ack==0)
return(0);
SendByte(suba); //發送器件子地址
if(ack==0)
return(0);
Start_I2c();
SendByte(sla+1);
if(ack==0)
return(0);
for(i=0;i<no-1;i++)
{
*s=RcvByte(); //發送數據
Ack_I2c(0); //發送就答位
s++;
}
*s=RcvByte();
Ack_I2c(1); //發送非應位
Stop_I2c(); //結束總線
return(1);
}
/****************************************************************/
//延時函數delay(),有形參Count用于控制延時函數執行次數,無返回值
/****************************************************************/
void Delay_MS(u16 Count)
{
u8 i,j;
while (Count--)//Count形參控制延時次數
{
for(i=0;i<100;i++)
for(j=0;j<40;j++);
}
}
void _Nop()//1us
{
unsigned char i;
_nop_();
_nop_();
_nop_();
i=1;
while(--i);
}
|