?? max7221(多路)2.c
字號:
#include <reg51.h> //AD7135直接與單片機相連 采用查詢的方法 多路
#include <absacc.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define ADP2 P2
#define ADP0 P0
#define CD4051 P1
#define fosc 12 // 晶振頻率
#define time0 2000 // 定時2000us
#define jishu 1000 // 假設AD輸入電壓與對應瞬時功率的基數
// 1V對應1000w
uint idata jisuandu; // 臨時變量,用于計算電度數
uint idata time0_0; // 臨時變量,用于計算定時
sbit STAT7135= P1^7; // 7135的啟動端
sbit busy = P2^6; // 7135的忙端
sbit st = P2^5; // 7135的選通端
sbit CS7221 = P1^5; // 7221的片選
sbit DIN7221 = P1^4; // 7221的數據端
sbit CLK7221 = P1^6; // 7221的時鐘端
sbit SDA=P3^1; //2416的數據端
sbit SCL=P3^0; //2416的時鐘端
//sbit en_24c16=P3^4;
uchar DISPBUF[8]={0,1,2,3,4,5,6,7}; //顯示緩沖區
uchar ADBUF[40]=0; //AD緩沖區 (萬千百十個)*8
uchar TIME[2]=0; //用于定時
uchar BUF[5]=0; //數據處理緩沖區
void delay(uint n); //延時子程序
void Initial7221(void); //MAX7221初始化
void WR7221(uchar addr,uchar Data); //MAX7221寫程序
void Max7221Display(uchar *buffer); //MAX7221顯示程序
void time2ms(void); //定時器0初始化程序
void time0_int(void); //定時器0中斷服務程序
void ICL7135(void); //ICL7135 8路信號AD轉換程序
void SAVE(void); //電量存儲 轉電度程序
void start_bit(void); //IIC開始條件
void stop_bit(void); //IIC停止條件
void mast_ack(void); //IIC應答
bit write_8bit(uchar ch); //IIC寫8位數據
uchar read24c16(uint address,uchar *shu); //IIC讀字節數據
uchar write24c16(uint address,uchar ddata); //IIC寫字節數據
uchar page_wr(uint firstw_ad,uint counter,uchar *firstr_ad);//IIC頁寫
uchar page_rd(uint firstrd_ad,uint count,uchar *firstwr_ad);//IIC頁讀
main()
{ //while(page_wr(0,120,0)==0); //初次使用時 清電量數
Initial7221(); //初始化7221
Max7221Display(&DISPBUF[0]); //開機默認顯示0~7
delay(40); //延時
time2ms(); //啟動定時器
while(1)
{
if(TIME[1]%10==0) //5秒時間到
{ ICL7135(); //啟動8路AD轉換
SAVE(); //存儲電能
}
}
}
void WR7221(uchar addr,uchar Data) //MAX7221的寫子程序
{
uchar i;
CS7221 = 0; //片選有效
for (i=0;i<8;i++) //寫8位地址
{
CLK7221 = 0; //時鐘低
DIN7221 = (addr&(0x80>>i)) ? 1:0; //先發高位 依次到低位
_nop_();
_nop_();
CLK7221 = 1; //時鐘高 上升沿鎖數據
_nop_();
_nop_();
}
for (i=0;i<8;i++) //寫8位數據
{
CLK7221 = 0; //時鐘低
DIN7221 = (Data&(0x80>>i)) ? 1:0; //先發高位 依次到低位
_nop_();
_nop_();
CLK7221 = 1; //時鐘高 上升沿鎖數據
_nop_();
_nop_();
}
CS7221 = 1; //片選無效
}
void Initial7221(void) //MAX7221初始化
{
WR7221(0x0A,0x0A); //亮度地址0AH,0x00~0x0F,0x0F最亮
WR7221(0x0B,0x07); //掃描LED個數地址0BH,0x00~0x07,最多掃描8個數碼管
WR7221(0x0C,0x01); //工作模式地址0x0C. 0x00:關斷;0x01:正常
WR7221(0x09,0xFF); //編碼模式地址0x09. 0x00~0xFF:哪一位為1,哪一位就支持編碼
}
void Max7221Display(uchar *buffer) //MAX7221顯示子程序
{
uchar i;
for (i=0;i<8;i++) //MAX7221的8個數碼管顯示
{
WR7221(i+1,*(buffer+i)); //調MAX7221的寫子程序
}
}
void delay(uint n) //延時程序
{
uint i,j;
for (i=0;i<n;i++)
for (j=0;j<1140;j++);
}
void time2ms(void) //T0定時器初始化
{
TMOD=0x01; // T0工作方式1
/* 2ms 定時設置 */
time0_0 = 65536-time0*fosc/12; //計算初值
TH0=(time0_0/256); //裝定時器0初值
TL0=(time0_0%256);
TR0=1; //啟動定時器0
ET0=1; //打開定時器0中斷
EA=1; //打開總中斷
}
/* 定時器0中斷服務子程序,定時用于AD轉換
1s約轉換3次,8路信號約3s時間
為了時間充裕 5s采集一次電能信號 */
void time0_int(void) interrupt 1
{
TH0=(time0_0/256); //重裝定時器0初值
TL0=(time0_0%256);
TIME[0]++;
if (TIME[0]==250) //250*2ms=500ms=0.5s時間到
{
TIME[0]=0; //到0.5s時 TIME[0]清0
TIME[1]++; //TIME[1]加1 內存的0.5秒的整數倍
}
}
void ICL7135(void) //啟動8路AD轉換
{
uchar i,j;
STAT7135=1; //7135啟動端使能 啟動AD轉換
CD4051=CD4051&0xf0; //設置CD4051的第一路信號輸入AD
for (j=0;j<=7;j++) //8路循環測量
{
i=CD4051&0xf0; //讀P1口的狀態 保護高位
CD4051=j|i; //通過j調節 多路開關的轉換
STAT7135=1; //7135啟動端使能 啟動AD轉換
i=busy; //讀7135的正在轉換 忙端
do{i=busy;}while(busy==0); //忙端為0時 等待 直到開始轉換
do{i=busy;}while(busy==1); //忙端為1時 正在轉換 等待
STAT7135=0; //7135 禁止AD轉換
do{i=ADP2;}while((ADP2&0x010)!=0x010); //讀7135的D5,直到D5為1
if ((ADP2&0x010)==0x010) //D5為1開始讀AD轉換結果
{
//STAT7135=0;
ADBUF[j*5]=ADP0&0x0f; //讀7135的萬位
do{i=ADP2;}while((ADP2&0x08)!=0x08);//讀7135的D4,直到D4為1
ADBUF[1+j*5]=ADP0&0x0f; //讀7135的千位
do{i=ADP2;}while((ADP2&0x04)!=0x04);//讀7135的D3,直到D3為1
ADBUF[2+j*5]=ADP0&0x0f; //讀7135的百位
do{i=ADP2;}while((ADP2&0x02)!=0x02);//讀7135的D2,直到D2為1
ADBUF[3+j*5]=ADP0&0x0f; //讀7135的十位
do{i=ADP2;}while((ADP2&0x01)!=0x01);//讀7135的D1,直到D1為1
ADBUF[4+j*5]=ADP0&0x0f; //讀7135的個位
//ADBUF[0]=j+1; //路號
//Max7221Display(&ADBUF[j*5]); //當頻率慢時可以顯示AD轉換的結果
}
}
}
void SAVE(void) //電能處理 保存
{
uchar k,i;
ulong kk,kk1,kk2;
if (TIME[1]<120) //小于1分鐘時 120*0.5=60s 簡單加
{
for (k=0;k<=7;k++) //8路電能循環存儲
{
while (page_rd(k*5,5,&BUF[0])==0); //讀原來的電能 各路5位數字
for (i=0;i<=4;i++)
{
BUF[i]=BUF[i]+ADBUF[i+k*5]; //本次的電能和原來的電能求和
}
while (page_wr(k*5,5,&BUF[0])==0); //存新的總電能
}
}
if (TIME[1]==120) //等于1分鐘時 做電度數的處理
{
TIME[1]=0;
for (k=0;k<=7;k++) //8路電能循環轉換成電度數 存儲
{
while (page_rd(k*5,5,&BUF[0])==0); //讀原來的電能 各路5位數字
for (i=0;i<=4;i++)
{
BUF[i]=BUF[i]+ADBUF[i+k*5]; //本次的電能和原來的電能求和
}
while (page_wr(k*5,5,0)==0); //清寄存的電能
kk=(ulong)BUF[0]*10000+(ulong)BUF[1]*1000+(ulong)BUF[2]*100+(ulong)BUF[3]*10+(ulong)BUF[4];
// 把電能轉化為千瓦時 即度
while(page_rd(100+k*2,2,&BUF[0])==0); //讀上次余數
kk=kk*jishu+(ulong)BUF[0]*100+(ulong)BUF[1];// (jishu*1000)/(10000*12*60)=jishu/7200
kk1=kk/7200; //取電度數
kk2=kk%7200; //kk1為電度數 kk2 余數
BUF[0]=(uchar)(kk2/100); //分兩部分存儲電度的余數 100為界
BUF[1]=(uchar)(kk2%100);
while(page_wr(100+k*2,2,&BUF[0])==0); //電度的存余數
while (page_rd(50+k*5,5,&BUF[0])==0); //讀原來電度數
kk1=kk1+(ulong)BUF[0]*10000+(ulong)BUF[1]*1000+(ulong)BUF[2]*100+(ulong)BUF[3]*10+(ulong)BUF[4];
//原來的電度和新的電度數相加
BUF[0]=(uchar)(kk1/10000); //萬
BUF[1]=(uchar)((kk1%10000)/1000); //千
BUF[2]=(uchar)(((kk1%10000)%1000)/100); //百
BUF[3]=(uchar)((kk1%100)/10); //十
BUF[4]=(uchar)((kk1%100)%10); //個
while(page_wr(50+k*5,5,&BUF[0])==0); //存新電度數
DISPBUF[0]=k+1; //顯示戶號
DISPBUF[1]=0xf; //顯示2個F
DISPBUF[2]=0xf;
DISPBUF[3]=BUF[0]; //顯示此時電度數
DISPBUF[4]=BUF[1];
DISPBUF[5]=BUF[2];
DISPBUF[6]=BUF[3];
DISPBUF[7]=BUF[4];
Max7221Display(&DISPBUF[0]); //送顯示
delay(20); //延時
}
}
}
/*-----------------------------------------------
調用方式:void start_bit(void)
函數說明:開始位
-----------------------------------------------*/
void start_bit(void)
{
SCL=1;_nop_();
SDA=1;_nop_();
SDA=0;_nop_();
SCL=0;_nop_();
}
/*-----------------------------------------------
調用方式:void stop_bit(void)
函數說明:停止位
-----------------------------------------------*/
void stop_bit(void)
{
SDA=0;_nop_();
SCL=1;_nop_();
SDA=1;_nop_();
}
/*-----------------------------------------------
調用方式:void mast_ack(void)
函數說明:主答函數
-----------------------------------------------*/
void mast_ack(void)
{
SCL=0;_nop_();
SDA=0;_nop_();
SCL=1;_nop_();
SCL=0;_nop_();
SDA=1;_nop_();
}
/*-----------------------------------------------
調用方式:write_8bit(uchar ch)
函數說明:寫一個字節(8位)數據
-----------------------------------------------*/
bit write_8bit(uchar ch)
{
uchar i=8;
bit fan_w;
SCL=0;_nop_();
while (i--)
{
SDA=(bit)(ch&0x80);_nop_();
ch<<=1;
SCL=1;_nop_();
SCL=0;_nop_();
}
SDA=1;_nop_();
SCL=1;_nop_();
fan_w=SDA;
SCL=0;_nop_();
return(fan_w);
}
/*----------------------------------------------
調用方式:uchar read24c16(uint address,uchar *shu)
函數說明:讀24c16指定地址數據(字節讀)
-----------------------------------------------*/
uchar read24c16(uint address,uchar *shu)
{
uchar data rdata;
uchar i=8;
EA=0;//避免與串口通訊等中斷沖突
start_bit();
if (write_8bit(0xA0)!=0){
stop_bit();EA=1;return(0);
}
if (write_8bit(address)!=0){
stop_bit();EA=1;return(0);
}
start_bit();
if (write_8bit(0xA1)!=0){
stop_bit();EA=1;return(0);
}
while (i--)
{
rdata<<=1;
SCL=1;_nop_();
if (SDA) rdata|=0x01;
SCL=0;_nop_();
}
stop_bit();
EA=1;
*shu=rdata;
return (1);
}
/*-----------------------------------------------
調用方式:void write24c16(uint address,uchar ddata)
函數說明:寫數據到24c16的指定地址(字節寫)
-----------------------------------------------*/
uchar write24c16(uint address,uchar ddata)
{
EA=0; //避免與串口通訊等中斷沖突
start_bit();
if (write_8bit(0xA0)!=0){
stop_bit();EA=1;return(0);
}
if (write_8bit(address)!=0){
stop_bit();EA=1;return(0);
}
if (write_8bit(ddata)!=0){
stop_bit();EA=1;return(0);
}
stop_bit();
EA=1;
return(1);
}
/*-----------------------------------------------
調用方式:void page_wr(uint firstw_ad,uint counter,uint data *firstr_ad)
函數說明:頁面寫函數,firstw_ad為寫入字節單元的首地址,
*firstr-ad為被寫入數據所在首地址指針
counter為寫入數據字節數
-----------------------------------------------*/
uchar page_wr(uint firstw_ad,uint counter,uchar *firstr_ad)
{
uchar data *ufirstr_ad;
ufirstr_ad=firstr_ad;
start_bit();
if (write_8bit(0xA0)!=0){
stop_bit();return(0);
}
if (write_8bit(firstw_ad)!=0){
stop_bit();return(0);
}
while (counter--)
{
if (write_8bit(*ufirstr_ad)!=0){
stop_bit();return(0);
}
ufirstr_ad++;
}
stop_bit();
return(1);
}
/*-----------------------------------------------
調用方式:void page_rd(uint firstrd_ad,uint count,uint firstwr_ad)
函數說明:頁面讀函數,firstrd-ad為所讀字節首地址,count為讀字節數
*ufirstwr-ad為讀出數據存儲首地址指針
-----------------------------------------------*/
uchar page_rd(uint firstrd_ad,uint count,uchar *firstwr_ad)
{
uchar j=8;
uchar data *ufirstwr_ad;
ufirstwr_ad=firstwr_ad;
start_bit();
if (write_8bit(0xA0)!=0){
stop_bit();return(0);
}
if (write_8bit(firstrd_ad)!=0){
stop_bit();return(0);
}
start_bit();
if (write_8bit(0xA1)!=0){
stop_bit();return(0);
}
while (count--)
{
uchar i=8;
while (i--)
{
(*ufirstwr_ad)<<=1;
SCL=1;_nop_();
if (SDA) (*ufirstwr_ad)|=0x01;
SCL=0; _nop_();
}
ufirstwr_ad++;
mast_ack();
}
while (j--)
{
(*ufirstwr_ad)<<=1;
SCL=0;_nop_();_nop_();SCL=1;
if (SDA) (*ufirstwr_ad)|=0x01;
}
stop_bit();
return(1);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -