#include "reg51.h"
#include "iic.h"
/*****************************独立按键部分************/
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
unsigned char keysta[] = {1,1,1,1};
void key_xiaodou();
void key_saomiao();
/*****************************独立按键部分************/
unsigned int count_f = 0; //用来计算NE555的频率 来一个脉冲+1
unsigned int count_out; //count_f 1s测出来的数值给到count_out 去显示在数码管上
unsigned int res = 0; //读出AD出来的值
unsigned int res1; // res 在 state_res = 1时给到res1 不然就给数值2
unsigned char state_res = 0; // 电压测量模式下 0:显示2v 1:显示测量的电压值
unsigned char state = 1; //数码管显示状态位
unsigned char LED_on = 1; //LED 开关状态标志位
unsigned char LED_state = 0; //LED 在开情况下的状态标志位
unsigned char SMG_on = 1; //数码管 开关状态标志位
unsigned char SMG_Value[17] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
0x88,0x83,0xC6,0xA1,0x86,0x8E,0xBF}; //0到F到-
unsigned char SMG_buff[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
void close_all(void)
{
P2 = 0x1f;
P0 = 0xFF;P2 = (P2 & 0x1F) | 0x80;P2 &= 0x1F; //关闭LED
P0 = 0x00;P2 = (P2 & 0x1F) | 0xa0;P2 &= 0x1F; //关闭蜂鸣器等Y5锁存对应的外设
P0 = 0x00;P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F; //关闭数码管位选
P0 = 0xFF;P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F; //关闭数码管段选
}
void Config_PCF8591() //ADC读取滑动变阻器当前电压值的数字量
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x03);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
res = IIC_RecByte();
IIC_WaitAck();
IIC_SendAck(0);
IIC_Stop();
}
void write_dac(unsigned char add) //DAC转换
{
EA=0;
IIC_Start();
IIC_SendByte(0X90);
IIC_WaitAck();
IIC_SendByte(0X40);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
EA=1;
}
void Init_Timer() //T0用作计数器 T1设置1ms定时器
{
TH0 = 0xff;
TL0 = 0xff;
TH1 = (65536 - 1000) / 256;
TL1 = (65536 - 1000) % 256;
TMOD = 0x16; //定时器1用方式1,定时;定时器0用方式2,计数
ET0 = 1;
ET1 = 1;
EA = 1;
TR0 = 1;
TR1 = 1;
}
void SMG_shuaxin(void) //放到中断里刷新去
{
static unsigned char i = 0;
P2 = 0x1F;
switch(i)
{
case 0:P0 = SMG_buff[0];P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F;
P0 = 0x01 << i; P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F;i++;break;
case 1:P0 = SMG_buff[1];P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F;
P0 = 0x01 << i; P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F;i++;break;
case 2:P0 = SMG_buff[2];P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F;
P0 = 0x01 << i; P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F;i++;break;
case 3:P0 = SMG_buff[3];P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F;
P0 = 0x01 << i; P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F;i++;break;
case 4:P0 = SMG_buff[4];P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F;
P0 = 0x01 << i; P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F;i++;break;
case 5:P0 = SMG_buff[5];P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F;
P0 = 0x01 << i; P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F;i++;break;
case 6:P0 = SMG_buff[6];P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F;
P0 = 0x01 << i; P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F;i++;break;
case 7:P0 = SMG_buff[7];P2 = (P2 & 0x1F) | 0xe0;P2 &= 0x1F;
P0 = 0x01 << i; P2 = (P2 & 0x1F) | 0xc0;P2 &= 0x1F;i=0;break;
}
}
unsigned char buf[8] = 0;
void SMG_display()//数码管显示函数
{
unsigned char j;
if(SMG_on == 1) //数码管工作状态
{
if(state == 0) //在频率测量状态
{
SMG_buff[0] = SMG_Value[15];
SMG_buff[1] = 0xFF;
SMG_buff[2] = 0xFF;
//******************** 高位零不显示 *************//
buf[7] = count_out%10;
buf[6] = count_out/10%10;
buf[5] = count_out/100%10;
buf[4] = count_out/1000%10;
buf[3] = count_out/10000%10;
//从最高位开始,遇到0不显示,遇到非0退出循环
for (j=3;j<=7;j++)
{
if (buf[j] == 0)
SMG_buff[j] = 0xFF;
else
break;
}
//将剩余的有效数字位如实转换
for ( ; j<=7; j++) //for()起始未对j操作,j即保持上个循环结束时的值
{
SMG_buff[j] = SMG_Value[buf[j]];
}
/*************************************************/
}
else if(state == 1) //在电压测量状态
{
SMG_buff[0] = ~0x3E;
SMG_buff[1] = 0xFF;
SMG_buff[2] = 0xFF;
SMG_buff[3] = 0xFF;
SMG_buff[4] = 0xFF;
SMG_buff[5] = SMG_Value[(res1)/100%10]^0x80; //255:5 每一份占0.02v
SMG_buff[6] = SMG_Value[(res1)/10%10];
SMG_buff[7] = SMG_Value[(res1)%10];
}
}
else if(SMG_on == 0) //数码管不工作
{
SMG_buff[1] = 0xFF;
SMG_buff[2] = 0xFF;
SMG_buff[3] = 0xFF;
SMG_buff[4] = 0xFF;
SMG_buff[5] = 0xFF;
SMG_buff[6] = 0xFF;
SMG_buff[7] = 0xFF;
SMG_buff[0] = 0xFF;
}
}
/*****************************独立按键部分************/
void key_saomiao() //独立按键扫描
{
static unsigned char backup[] = {1,1,1,1};
if(keysta[0] != backup[0])
{
if(backup[0] == 0)
{
// S7按下弹起 执行代码
SMG_on++;
if(SMG_on >= 2)
{
SMG_on = 0;
}
}
backup[0] = keysta[0];
}
if(keysta[1] != backup[1])
{
if(backup[1] == 0)
{
// S6按下弹起 执行代码
LED_on++;
if(LED_on >= 2)
{
LED_on = 0;
}
}
backup[1] = keysta[1];
}
if(keysta[2] != backup[2])
{
if(backup[2] == 0)
{
// S5按下弹起 执行代码
state_res++;
if(state_res >= 2)
{
state_res = 0;
}
}
backup[2] = keysta[2];
}
if(keysta[3] != backup[3])
{
if(backup[3] == 0)
{
// S4按下弹起 执行代码
state++;
if(state >= 2)
{
state = 0;
}
}
backup[3] = keysta[3];
}
}
void key_xiaodou() //独立按键消抖
{
static unsigned char keybuf[] = {0xFF,0xFF,0xFF,0xFF};
static unsigned char i;
keybuf[0] = (keybuf[0] << 1) | S7;
keybuf[1] = (keybuf[1] << 1) | S6;
keybuf[2] = (keybuf[2] << 1) | S5;
keybuf[3] = (keybuf[3] << 1) | S4;
for(i=0;i<4;i++)
{
if((keybuf[i] & 0x0F) == 0x00)
{
keysta[i] = 0;
}
else if((keybuf[i] & 0x0F) == 0x0F)
{
keysta[i] = 1;
}
}
}
void LED_Display() //LED显示
{
if(LED_on == 0) //LED不工作
{
P2 = 0x1F;P0 = 0xFF; P2 = 0x80; P2 = 0x1F;
}
else if(LED_on == 1) //LED工作
{
if(state == 0) //在频率测量状态下
{
if(LED_state == 2) //处在L4灭的区间内
{
P2 = 0x1F;P0 = 0xFD;P2 = 0x80; P2 = 0x1F;
}
else if(LED_state == 3) //处在L4亮的区间内
{
P2 = 0x1F;P0 = 0xF5;P2 = 0x80; P2 = 0x1F;
}
}
else if(state == 1) //在电压测量状态下
{
if(state_res == 1) //处在动态测量 L5要亮
{
if(LED_state == 0)//处在L3灭的区间
{
P2 = 0x1F;P0 = 0xEE;P2 = 0x80; P2 = 0x1F;
}
else if(LED_state == 1)//处在L3亮区间
{
P2 = 0x1F;P0 = 0xEA;P2 = 0x80; P2 = 0x1F;
}
}
else //处在只显示2v的状态
{
P2 = 0x1F;P0 = 0xFE;P2 = 0x80; P2 = 0x1F;
}
}
}
}
/*****************************独立按键部分************/
void Service_T0() interrupt 1
{
count_f++;
}
unsigned int dat = 0;
unsigned int dat1 = 0;
void Service_T1() interrupt 3
{
TH1 = (65536 - 1000) / 256;
TL1 = (65536 - 1000) % 256;
dat++; //用于计1s
dat1++; //用于计0.5s
if(dat1 >= 500)
{
Config_PCF8591(); //每0.5s读ADC出来的值
if(state_res == 0)
{
res1 = 200; // 表示2v 数码管第三个显示为个位
}
else if(state_res == 1)
{
res1 = res*2;//8位ADC 255:5v 数字量没一份占电压为0.0196... 这里当做0.02 放大100倍 直接以整形显示在数码管上 因为数码管第三个显示为个位
}
dat1 = 0;
}
if(dat >= 1000)
{
count_out = count_f; //将1s计数的脉冲总数 给到count_out 用于后面数码管显示 说白了就是1s读一次频率值
count_f = 0; //计数值置0 准备下一秒计脉冲数
dat = 0;
SMG_display(); //数码管数值刷新放到中断里 就是1s刷一次
}
SMG_shuaxin();
key_xiaodou();
LED_Display(); //LED的显示在放while(1)里会存在微亮的情况 放1ms中断里不会有
write_dac(res);
//判断部分 可以单独写一个函数
if(state == 1) //在电压测量状态
{
if((res1 < 150) || ((res1 >= 250)&&(res1 <= 350)))
{
LED_state = 0;
}
else
{
LED_state = 1;
}
}
else if(state == 0) //在频率显示状态
{
if((count_out < 1000) || ((count_out >= 5000)&&(count_out<10000)))
{
LED_state = 2;
}
else
{
LED_state = 3;
}
}
}
void main()
{
close_all();
Init_Timer();
while(1)
{
key_saomiao();
}
}
以上代码,加上蓝桥官方2021提供的IIC底层文件编译应该没啥问题。bz编写习惯上可能有些陋习。如有错误,望指正。有看不懂的地方也可以提出来。