目录
前言
省赛相比与国赛确实要简单不少,但是一些小细节还是得注意
一、题目
这么高清的题目确定不点赞吗哈哈哈,你们的支持是我最大的动力
二、上代码
1、按键、数码管、LED、定时器等等模块代码(under)
1.1、under.c
#include <STC15F2K60S2.H>
unsigned char code t_display[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位码
unsigned char code keys_num[2][2]=//键盘的键值,只用了四个按键
{
12,16,
13,17,
};
unsigned char P_DIG;
unsigned char DIG1[8]={25,16,16,16,16,16,16,16};
unsigned char DIG2[8]={24,16,16,16,16,16,16,16};
unsigned char DIG3[8]={22,16,16,16,16,16,16,16};
unsigned char *DIG=DIG1;
unsigned char key_num;
unsigned char key_state;
unsigned char LED_state=0x00;//改变这个变量就可直接控制LED
void H138_mode(unsigned char mode)//138译码器选择端口
{
switch(mode)
{
case 4:P2=P2&0X1F|0X80;P2&=0X1F;break;
case 5:P2=P2&0X1F|0Xa0;P2&=0X1F;break;
case 6:P2=P2&0X1F|0Xc0;P2&=0X1F;break;
case 7:P2=P2&0X1F|0Xe0;P2&=0X1F;break;
}
}
void shumaguan()//数码管的函数
{
P0=0X00;
H138_mode(6);
P0=~t_display[DIG[P_DIG]];
H138_mode(7);
P0=T_COM[P_DIG];
H138_mode(6);
if(++P_DIG>7)P_DIG=0;
}
void LED()
{
P0=~LED_state;
H138_mode(4);
}
void init()//最开始的初始化,关蜂鸣器和LED
{
P0=0X00;
H138_mode(5);
P0=0XFF;
H138_mode(4);
}
void keys()//矩阵键盘
{
unsigned char R=255,C=255;//R是行,C是列
P3=0X0F;
P4=0X00;
if(~P3&0x0f)
{
if(key_state<255)key_state++;//按键扫描状态,每10ms扫描一次,用来消抖
if(P33==0)R=0;//先扫描行
if(P32==0)R=1;
P3=0XF0;
P4=0XFF;
if(P35==0)C=0;//再扫描列
if(P34==0)C=1;
if(R!=255&&C!=255)
{
key_num=keys_num[R][C];//最后找到最开始的键码值
}
}
else
{
key_num=0;
key_state=0;
}
}
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初值
TH0 = 0xD1; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=ET0=1;
}
1.2、under.h
#ifndef __under_H__
#define __under_H__
void H138_mode(unsigned char mode);
void shumaguan();
void LED();
void init();
void keys();
void Timer0Init(void);
extern unsigned char DIG1[8];//第一个界面显示
extern unsigned char DIG2[8];//第一个界面显示
extern unsigned char DIG3[8];//第一个界面显示
extern unsigned char *DIG;
extern unsigned char key_num;
extern unsigned char key_state;
extern unsigned char LED_state;
#endif
2、iic
2.1、iic.c
一些底层驱动就每贴上来,反正都一样
unsigned char ADC()//AD转换
{
unsigned char Byte;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x43);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
I2CReceiveByte();
I2CSendAck(0);
Byte=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return Byte;
}
void write_eeprom(unsigned char address,unsigned char Data)//写入eeprom
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(Data);
I2CWaitAck();
I2CStop();
}
unsigned char read_eeprom(unsigned char address)//读出eeprom
{
unsigned char Byte;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
Byte=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return Byte;
}
2.2、iic.h
#ifndef __iic_H__
#define __iic_H__
void write_eeprom(unsigned char address,unsigned char Data);
unsigned char read_eeprom(unsigned char address);
unsigned char ADC();
#endif
3、最重要的main来咯
写得比较详细,而且抖音注释,不懂的可以留言哦
#include <STC15F2K60S2.H>
#include "under.h"
#include "iic.h"
unsigned char time_10ms;//大循环,10ms进入一次,用来键盘消抖
unsigned char time_100ms;//拿来刷新ADC的,100ms读一次数据,要不然有点快
unsigned int time_5s;
unsigned char disp_mode;//界面切换变量
int volt_set;//电压参数变量
unsigned char count;//计数参数
unsigned int ADC_read;//读AD转换的变量
unsigned char void_key;//记录无效按键
bit flag;//计数用的标志位
bit compara_bit;//电压显示与电压参数比较标志位
void main()
{
init();
Timer0Init();
volt_set=read_eeprom(0)*10;//上电读书存入的电压参数
while(1)
{
if(time_10ms>=10)
{
time_10ms=0;
/*input*/
keys();
if(time_100ms>=100)
{
time_100ms=0;
ADC_read=ADC()/255.00*500;//电压扩大100倍,后面好显示
}
/*process*/
if(key_num==12&&key_state==2)//界面切换
{
disp_mode++;
disp_mode%=3;
if(disp_mode==2)//退出参数界面存电压参数
{
write_eeprom(0,volt_set/10);
}
void_key=0;//key_12整个程序始终有效
}
if(disp_mode==0)//电压显示界面
{
if((key_num==13&&key_state==2)||(key_num==16&&key_state==2)||(key_num==17&&key_state==2))//无效按键
{
void_key++;
}
}
if(disp_mode==1)//电压参数设置
{
if(key_num==16&&key_state==2)//有效按键
{
volt_set+=50;
if(volt_set>500)
{
volt_set=0;
}
void_key=0;
}
if(key_num==17&&key_state==2)//有效按键
{
volt_set-=50;
if(volt_set<0)
{
volt_set=500;
}
void_key=0;
}
if((key_num==13&&key_state==2))//无效按键
{
void_key++;
}
}
if(disp_mode==2)//计数清零设置
{
if(key_num==13&&key_state==2)//有效按键
{
count=0;
void_key=0;
}
if((key_num==16&&key_state==2)||(key_num==17&&key_state==2))//无效按键
{
void_key++;
}
}
//判断计数++
if(ADC_read>volt_set)
{
flag=1;
}
if(flag==1&&(ADC_read<volt_set))
{
count++;
flag=0;
}
/*output*/
/*数码管输出*/
if(disp_mode==0)//第一个界面
{
DIG=DIG1;
DIG1[5]=ADC_read/100+32;
DIG1[6]=ADC_read/10%10;
DIG1[7]=ADC_read%10;
}
else if(disp_mode==1)//第二个界面
{
DIG=DIG2;
DIG2[5]=volt_set/100+32;
DIG2[6]=volt_set/10%10;
DIG2[7]=volt_set%10;
}
else//第三个界面
{
DIG=DIG3;
DIG3[6]=count/10;
DIG3[7]=count%10;
}
/**LED输出*/
if(ADC_read<volt_set)
{
compara_bit=1;
}
else
{
compara_bit=0;
time_5s=0;
LED_state&=~0X01;//L1灭
}
if(time_5s>=5000)//判断五秒后是否标志位为1
{
if(compara_bit==1)
{
LED_state|=0X01;//L1亮
}
}
if(count%2!=0)//判断是奇数
{
LED_state|=0X02;
}
else
{
LED_state&=~0X02;
}
/*判断无效按键*/
if(void_key>=3)
{
LED_state|=0X04;
}
else
{
LED_state&=~0X04;
}
}
}
}
void timer0(void) interrupt 1
{
time_10ms++;
time_100ms++;
if(compara_bit==1)time_5s++;
shumaguan();
LED();
}
总结
这里的键盘只用了四个按键,不知道无效按键算不算除了这四个其他的按键,这里值得思索,还有计数值是曲线下降时的时候记一次数。
有不理解的地方欢迎留言哦。