综述
第七届初赛赛题除了基础的独立按键、数码管显示、继电器和蜂鸣器的控制、LED灯的控制以外,难度增加的部分体现在ds18b20的调用,同时增加了PWM波的考点。
本解析不代表标准答案或官方答案,仅做分享。若有不足或是更好的写法,望在评论区进行指正!
模板搭建
基础的功能:
1、独立按键
2、数码管显示
可以独立于赛题,提前写好,适用于各类赛题,仅做修改即可。
模板部分代码与解释在第三届赛题分享中
模板代码
程序设计
ds18b20
ds18b20的调用参考第五届赛题
链接
PWM波
这里题目描述——由P34口输出PWM波。然而PWM的输出端口并非P34。也就意味着,我们可以通过定时器来进行PWM波的输出。PWM波实际上就是占空比不同的方波信号,具体解释可以不再赘述。
题目要求是1kHz
的PWM波,也就是周期为1ms
,而占空比分别为20%、30%、70%,也就意味着我们的定时器最大只能取100μs
。也就是10个定时器周期里面,控制每个周期P34输出电平的高低来实现PWM波的输出。
代码:
void Timer0Init(void){
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xAE; //设置定时初值
TH0 = 0xFB; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void timer0() interrupt 1{
if(count == 9){
P34 = 1;
count = 0;
t ++;
if(t == 999){
t = 0;
if(sec > 0) sec --;
}
}
else if(count == (per[windMod] - 1)){
P34 = 0;
}
count ++;
}
其中sec表示的是秒计时,每按一次S5,sec自增60。
系统设计
在系统设计的时候,尽量避免对P2的重复操作。第三届系统设计示例
此题的相对于前面几届,系统的设计非常简单,只有一种模式,按下S4时只需要对显示内容进行修改即可,不需要对其他内容进行修改。
主函数代码:
#include <stc15f2k60s2.h>
#include <intrins.h>
#include <ds18b20.h>
#define uchar unsigned char
uchar keyPress[4] = {0, 0, 0, 0};
uchar keyPressFlag[4] = {0, 0, 0, 0};
uchar code shapeOfNum[12] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xbf, 0xc6};
uchar numGrp[8] = {11, 0, 5, 0, 0, 0, 0, 0};
uchar per[3] = {2, 3, 7};
uchar windMod = 0;
int count = 0, t = 0, sec = 0;
void Delay1ms(){
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void Delay5ms(){
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void openP2(uchar num){
P2 &= 0x1f;
P2 |= (num << 5);
}
void showNum(){
uchar i;
for(i = 0; i < 8; i ++){
if(numGrp[i] != 12){
openP2(6);P0 = (0x01 << i);
openP2(7);P0 = shapeOfNum[numGrp[i]];
Delay1ms();
}
}
openP2(6);P0 = 0x00;
}
void keyScan(){
uchar i;
for(i = 0; i < 4; i ++) keyPress[i] = 0;
if((P3 & 0x0f) != 0x0f){
Delay5ms();
if((P3 & 0x0f) != 0x0f){
switch(P3 & 0x0f){
case 0x0e:keyPressFlag[0] = 1;break;
case 0x0d:keyPressFlag[1] = 1;break;
case 0x0b:keyPressFlag[2] = 1;break;
case 0x07:keyPressFlag[3] = 1;break;
}
}
}
for(i = 0; i < 4; i ++){
if(keyPressFlag[i] != 0){
if((P3 & 0x0f) == 0x0f){
keyPress[i] = 1;
keyPressFlag[i] = 0;
}
}
}
}
uchar getTemp(){
uchar high, low;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Delay_OneWire(20);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
low = Read_DS18B20();
high = Read_DS18B20();
return ((high << 4) | (low >> 4));
}
void Timer0Init(void){
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xAE; //设置定时初值
TH0 = 0xFB; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void timer0() interrupt 1{
if(count == 9){
P34 = 1;
count = 0;
t ++;
if(t == 999){
t = 0;
if(sec > 0) sec --;
}
}
else if(count == (per[windMod] - 1)){
P34 = 0;
}
count ++;
}
void main(){
uchar sys = 1, showMod = 0, temp;
P2 = 0xa0;P0 = 0x00;
P2 = 0x80;P0 = 0xff;
Timer0Init();
EA = 1;ET0 = 0;
getTemp();
while(1){
keyScan();
if(sec == 0){
if(sys == 1){
ET0 = 0;
sys = 0;
}
}
else{
if(sys == 0){
Timer0Init();
ET0 = 1;
sys = 1;
}
}
if(keyPress[2] == 1){
sec += 60;
}
if(keyPress[1] == 1){
sec = 0;
}
if(keyPress[0] == 1){
windMod = (windMod + 1) % 3;
}
if(keyPress[3] == 1){
showMod = !showMod;
}
if(showMod == 0){
//数码管显示
numGrp[0] = 10;
numGrp[1] = windMod + 1;
numGrp[2] = 10;
numGrp[3] = 12;
numGrp[4] = sec / 1000;
numGrp[5] = (sec / 100) % 10;
numGrp[6] = (sec / 10) % 10;
numGrp[7] = sec % 10;
}
else{
temp = getTemp();
//数码管显示
numGrp[0] = 10;
numGrp[1] = 4;
numGrp[2] = 10;
numGrp[3] = 12;
numGrp[4] = 12;
numGrp[5] = temp / 10;
numGrp[6] = temp % 10;
numGrp[7] = 11;
}
showNum();
}
}