#include
#include "iic.h"
#define uchar unsigned char //定义无符号字符类型uchar
#define uint unsigned int //定义无符号整型类型uint
uchar code tab[]={
0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,//0~9数字
0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10,//0~9数字带小数点
0XBF,0XFF,0XC1,0X8C,0XC8};//“-”“关”“U”“P”“N”
uchar temp,L1=0;
uchar yi,er,san,si,wu,liu,qi,ba;
uint dianya,Vp,trie=0,jishu=0,dianya_tt=0;
uchar yemian=0,key_no=0;
bit bz=0,L1_kai=0;
void delayms(int ms); //延时函数
void allinit(); //初始化函数
void keyscan16(); //矩阵按键函数
void display1(uchar yi,uchar er); //第一、二段数码管函数
void display2(uchar san,uchar si); //第三、四段数码管函数
void display3(uchar wu,uchar liu); //第五、六段数码管函数
void display4(uchar qi,uchar ba); //第七、八段数码管函数
void Timer0Init(void); //5毫秒@12.000MHz
void main()
{
allinit(); //初始化函数
Timer0Init(); //初始化定时器0
Vp=EEPROM_read(0x00)*10; //从EEPROM中读取电压参数
while(1)
{
if((dianya_tt==10)||(dianya_tt==20)) //电压采样
{
dianya=AD_read(0x03)*1.961;
}
if(yemian==0) //数据界面
{
yi=22;er=21;san=21;si=21;wu=21;liu=dianya/100+10;qi=dianya%100/10;ba=dianya%10;
}
else if(yemian==1) //参数界面
{
yi=23;er=21;san=21;si=21;wu=21;liu=Vp/100+10;qi=Vp%100/10;ba=Vp%10;
}
else if(yemian==2) //计数界面
{
if(jishu>=1000000){
yi=24;er=jishu/1000000;san=jishu%1000000/100000;si=jishu%100000/10000;wu=jishu%10000/1000;liu=jishu%1000/100;qi=jishu%100/10;ba=jishu%10;}
else if(jishu>=100000){
yi=24;er=21;san=jishu/100000;si=jishu%100000/1000;wu=jishu%10000/1000;liu=jishu%1000/100;qi=jishu%100/10;ba=jishu%10;}
else if(jishu>=10000){
yi=24;er=21;san=21;si=jishu/10000;wu=jishu%10000/1000;liu=jishu%1000/100;qi=jishu%100/10;ba=jishu%10;}
else if(jishu>=1000){
yi=24;er=21;san=21;si=21;wu=jishu/1000;liu=jishu%1000/100;qi=jishu%100/10;ba=jishu%10;}
else if(jishu>=100){
yi=24;er=21;san=21;si=21;wu=21;liu=jishu/100;qi=jishu%100/10;ba=jishu%10;}
else if(jishu>=10){
yi=24;er=21;san=21;si=21;wu=21;liu=21;qi=jishu/10;ba=jishu%10;}
else if(jishu>=0){
yi=24;er=21;san=21;si=21;wu=21;liu=21;qi=21;ba=jishu;}
}
if(dianya<Vp){
L1=1;} //判断什么时候L1灯亮
else {
L1=0;trie=0;}
if(L1_kai==1){
P2=0X80;P0&=0XFE;} //控制L1熄灭/亮起状态
else if(L1_kai==0){
P2=0X80;P0|=0X01;}
if(dianya>Vp)bz=1; //下降沿计数
if(bz==1){
if(dianya<=Vp){
bz=0;jishu=jishu+1;}}
if(jishu%2==1){
P2=0X80;P0&=0XFD;} //奇数时L2灯亮,否则熄灭
else {
P2=0X80;P0|=0X02;}
if(key_no>=3){
P2=0X80;P0&=0XFB;} //无效按键判断次数,控制L3灯熄灭/亮起状态
else {
P2=0X80;P0|=0X04;}
keyscan16(); //矩阵按键函数
display1(yi,er); //第一、二段数码管函数
display2(san,si); //第三、四段数码管函数
display3(wu,liu); //第五、六段数码管函数
display4(qi,ba); //第七、八段数码管函数
}
}
void Timer0Init(void) //5毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xA0; //设置定时初值
TH0 = 0x15; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA = 1;ET0 = 1;
}
void time0() interrupt 1
{
if(L1==1) //L1灯亮起标志
{
if(++trie==1000) //延时5秒钟
{
trie=0;L1_kai=1;
}
}
else if(L1==0) //L1灯关闭标志
{
L1_kai=0;
}
if(++dianya_tt==20) //电压采样时间
{
dianya_tt=0;
}
}
void keyscan16()//矩阵按键函数
{
uchar temp; //定义一个无符号变量temp
P44=0;P42=1;P3=0x7f; //让第一列按键为低电平
temp=P3; //把P3的值赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
if(temp!=0x0f) //判断第一列是否有按键按下
{
delayms(5); //延时5ms,用来按键消抖
temp=P3; //把P3的值重新赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
if(temp!=0x0f) //再次判断第一列是否有按键按下
{
temp=P3; //把P3的值重新赋给temp
switch(temp)
{
case 0x7e:key_no=key_no+1;break; //第一列第一个按键按下,无效按键次数加1
case 0x7d:key_no=key_no+1;break; //第一列第二个按键按下,无效按键次数加1
case 0x7b:key_no=key_no+1;break; //第一列第三个按键按下,无效按键次数加1
case 0x77:key_no=key_no+1;break; //第一列第四个按键按下,无效按键次数加1
}
while(temp!=0x0f) //无按键按下则进入循环
{
temp=P3; //把P3的值重新赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
}
}
}
P44=1;P42=0;P3=0xbf; //让第二列按键为低电平
temp=P3; //把P3的值赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
if(temp!=0x0f) //判断第一列是否有按键按下
{
delayms(5); //延时5ms,用来按键消抖
temp=P3; //把P3的值重新赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
if(temp!=0x0f) //再次判断第一列是否有按键按下
{
temp=P3; //把P3的值重新赋给temp
switch(temp)
{
case 0xbe:key_no=key_no+1;break; //第二列第一个按键按下,无效按键次数加1
case 0xbd:key_no=key_no+1;break; //第二列第二个按键按下,无效按键次数加1
case 0xbb:key_no=key_no+1;break; //第二列第三个按键按下,无效按键次数加1
case 0xb7:key_no=key_no+1;break; //第二列第四个按键按下,无效按键次数加1
}
while(temp!=0x0f) //无按键按下则进入循环
{
temp=P3; //把P3的值重新赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
}
}
}
P44=1;P42=1;P3=0xdf; //让第三列按键为低电平
temp=P3; //把P3的值赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
if(temp!=0x0f) //判断第一列是否有按键按下
{
delayms(5); //延时5ms,用来按键消抖
temp=P3; //把P3的值重新赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
if(temp!=0x0f) //再次判断第一列是否有按键按下
{
temp=P3; //把P3的值重新赋给temp
switch(temp)
{
case 0xde:key_no=key_no+1;break; //第三列第一个按键按下,无效按键次数加1
case 0xdd:key_no=key_no+1;break; //第三列第二个按键按下,无效按键次数加1
case 0xdb:
key_no=0;jishu=0; //无效按键次数清零,计数清零
break;
case 0xd7:
key_no=0; //数据界面进入到参数界面
if(yemian==0)yemian=1; //数据界面进入到参数界面
else if(yemian==1){
yemian=2;EEPROM_write(0x00,Vp/10);delayms(2);} //参数界面进入到计数界面,把电压参数保存到EEPROM中
else if(yemian==2){
yemian=0;} //计数界面进入到数据界面
break;
}
while(temp!=0x0f) //无按键按下则进入循环
{
temp=P3; //把P3的值重新赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
}
}
}
P44=1;P42=1;P3=0xef; //让第四列按键为低电平
temp=P3; //把P3的值赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
if(temp!=0x0f) //判断第一列是否有按键按下
{
delayms(5); //延时5ms,用来按键消抖
temp=P3; //把P3的值重新赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
if(temp!=0x0f) //再次判断第一列是否有按键按下
{
temp=P3; //把P3的值重新赋给temp
switch(temp)
{
case 0xee:key_no=key_no+1;break; //第四列第一个按键按下,无效按键次数加1
case 0xed:key_no=key_no+1;break; //第四列第二个按键按下,无效按键次数加1
case 0xeb:
key_no=0; //数据界面进入到参数界面
if(yemian==1)
{
if(Vp<=0)Vp=500;
else Vp=Vp-50; //每次按键后电压参数-0.5V
}
break;
case 0xe7:
key_no=0; //数据界面进入到参数界面
if(yemian==1)
{
if(Vp>=500)Vp=0;
else Vp=Vp+50; //每次按键后电压参数+0.5V
}
break;
}
while(temp!=0x0f) //无按键按下则进入循环
{
temp=P3; //把P3的值重新赋给temp
temp=temp&0x0f; //把temp的值和0x0f相与,得到的值再赋给temp,依次来判断第一列是否有按键按下
}
}
}
}
void delayms(int ms)//延时函数
{
uint i,j;
for(i=ms;i>0;i--)
for(j=845;j>0;j--);
}
void allinit()//初始化函数
{
P2=0XA0;P0=0X00; //关闭蜂鸣器继电器
P2=0X80;P0=0XFF; //关闭所有LED灯
P2=0XC0;P0=0XFF; //选中所有数码管段选
P2=0XFF;P0=0XFF; //关闭所有数码管
}
void display1(uchar yi,uchar er)//第一、二段数码管函数
{
P2=0XC0;P0=0X01; //选中第一个数码管位选
P2=0XFF;P0=tab[yi]; //让第一个数码管显示yi指向的值
delayms(1); //延时1ms
P2=0XC0;P0=0X02; //选中第二个数码管位选
P2=0XFF;P0=tab[er]; //让第一个数码管显示er指向的值
delayms(1); //延时1ms
}
void display2(uchar san,uchar si)//第三、四段数码管函数
{
P2=0XC0;P0=0X04; //选中第s三个数码管位选
P2=0XFF;P0=tab[san]; //让第一个数码管显示san指向的值
delayms(1); //延时1ms
P2=0XC0;P0=0X08; //选中第四个数码管位选
P2=0XFF;P0=tab[si]; //让第一个数码管显示si指向的值
delayms(1); //延时1ms
}
void display3(uchar wu,uchar liu)//第五、六段数码管函数
{
P2=0XC0;P0=0X10; //选中第五个数码管位选
P2=0XFF;P0=tab[wu]; //让第一个数码管显示wu指向的值
delayms(1); //延时1ms
P2=0XC0;P0=0X20; //选中第六个数码管位选
P2=0XFF;P0=tab[liu]; //让第一个数码管显示liu指向的值
delayms(1); //延时1ms
}
void display4(uchar qi,uchar ba)//第七、八段数码管函数
{
P2=0XC0;P0=0X40; //选中第七个数码管位选
P2=0XFF;P0=tab[qi]; //让第一个数码管显示qi指向的值
delayms(1); //延时1ms
P2=0XC0;P0=0X80; //选中第八个数码管位选
P2=0XFF;P0=tab[ba]; //让第一个数码管显示ba指向的值
delayms(1); //延时1ms
P2=0XC0;P0=0X80; //选中第八个数码管位选
P2=0XFF;P0=0XFF; //让第八个数码管熄灭
}
iic.c程序
#include
#include "iic.h"
#include "intrins.h"
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}
//等待应答
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA)
{
SCL = 0;
IIC_Stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;
}
unsigned char AD_read(unsigned char add)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Stop();
return temp;
}
unsigned char EEPROM_read(unsigned char add)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0xA0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0xA1);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Stop();
return temp;
}
void EEPROM_write(unsigned char add,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xA0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
iic.h程序
#ifndef _IIC_H
#define _IIC_H
//函数声明
void IIC_Start(void);
void IIC_Stop(void);
void IIC_SendByte(unsigned char byt);
bit IIC_WaitAck(void);
unsigned char IIC_RecByte(void);
unsigned char AD_read(unsigned char add);
unsigned char EEPROM_read(unsigned char add);
void EEPROM_write(unsigned char add,unsigned char dat);
#endif
第十一届蓝桥杯单片机(第一场)作品演示