第十三届蓝桥杯电子类单片机设计与开发程序题个人解答
题目资源
链接:https://pan.baidu.com/s/1DwLiSF4KgkobTsNhdIl4Ew
提取码:wk7v
个人完整参赛代码:
个人水平较低,如发现问题请予以告知,谢谢!
主函数
main.c
#include"stc15f2k60s2.h"
#include"ds1302.h"
#include"onewire.h"
#define uchar unsigned char
#define uint unsigned int
//数码管相关
uchar code dis_code[13]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xc1,0xbf,0xff};//0~9 u - 0xff
uchar dis_com=0;//数码管位选
uchar dis_buf[8]={10,1,12,12,12,12,12,12};//数码管缓冲区
uchar dis_mode=0;//数码管显示模式 0-温度 1-时间 2-参数
//按键相关
bit key_flag=0;//按键扫描标志
uchar key_state=0;//按键状态标志
uchar key_cnt=0;//按键每10ms扫描一次
//温度相关
bit tem_flag=0;//温度扫描标志
bit tem_state=0;//温度状态
uchar tem_para=23;//温度参数
uint tem_cnt=0;//设置11位工作方式,最大转换时间为375ms
float tem_value=0;//读取的温度
//时间相关
bit ds_int=0;//当前时间是否为整点
bit ds_flag=0;//时间读取 标志
bit ds_mode=0;//显示模式,0-时 分 1-分 秒
uint ds_cnt=0;//每100ms刷新一次时间
uchar* ds_value;//指向读取的时间
//继电器相关 (RELAY_SPDT)
bit re_mode=0;//工作模式 0-温度控制 1-时间控制
bit re_flag=0;//继电器时间控制模式下的工作标志
uchar re_cnt0=0;//继电器在整点吸合5s 每1毫秒re_cnt0加1 加到250则re_cnt1加1
uchar re_cnt1=0;//re_cnt1加到20则说明继电器已吸合5s,该关闭了
//LED相关
bit L_flag=0;//LED工作标志
uchar L_cnt=0;//LED每50ms转换一次
bit L1_flag=0;//L1启动标志
uchar L1_cnt0=0;//L1在整点时亮5s 这个参数用来计时,每250ms L1_cnt1加1
uchar L1_cnt1=0;//加到20则说明过了5s
bit L3_flag=0;//L3工作标志
bit L3_state=0;//L3当前亮灭状态
uchar L3_cnt=0;//继电器开启状态下,L3以0.1s为间隔闪烁
void init();//初始化函数
void cls_buzz();//关闭蜂鸣器函数
void display();//数码管动态显示函数
void scan_key();//按键扫描函数
void update();//数据更新函数
void dis_change();//数码管显示改变函数
void led();//LED函数
void re();//继电器函数
void timer0() interrupt 1{//中断 定时器0 1ms
TL0=0x18;
TH0=0xfc;
if(key_flag==0&&++key_cnt>=10){
key_flag=1;
key_cnt=0;
}
if(tem_flag==1&&++tem_cnt>=375){
tem_flag=0;
tem_cnt=0;
tem_state=1;
}
if(ds_flag==0&&++ds_cnt>=100){
ds_flag=1;
ds_cnt=0;
}
if(L1_flag==1&&++L1_cnt0>=250){
L1_cnt0=0;
L1_cnt1++;
}
if(L_flag==0&&++L_cnt>=50){
L_flag=1;
L_cnt=0;
}
if(L3_flag==1&&++L3_cnt>=100){
L3_state=~L3_state;
L3_cnt=0;
}
if(re_flag==1&&++re_cnt0>=250){
re_cnt0=0;
re_cnt1++;
}
display();
}
void main(){//主函数
init();//初始化
while(1){//主循环
update();//不断更新数据
}
}
void update(){
uint num;
if(key_flag==1){//按键
scan_key();
key_flag=0;
}
if(tem_flag==0&&tem_state==0){//温度
tem_start_convert();
tem_flag=1;
}
else if(tem_state==1){//温度
tem_value=rd_tem();
tem_state=0;
dis_change();
num=tem_value*10;
}
if(ds_flag==1){//时间
ds_value=read_ds1302();
if(( ds_value[2]+ds_value[3]+ds_value[4]+ds_value[5] )==0){
ds_int=1;//整点
}
else{
ds_int=0;//非整点
}
ds_flag=0;
dis_change();
}
if(L_flag==1){
re();//将继电器函数放在这里是为了减少代码量
led();
L_flag=0;
}
return;
}
void dis_change(){
bit sign=0;//符号位
uchar num;
uint t_uint;
for(num=1;num<8;num++){//数码管清零
dis_buf[num]=12;
}
if(dis_mode==0){//温度显示
dis_buf[1]=1;
if(tem_value>=0){//取1小数
t_uint=tem_value*10;
}
else{
sign=1;
t_uint=tem_value*(-10);
}
if(t_uint>=100){//题设数码管2.3.4熄灭,所以不考虑温度小于等于负10度的情况(考虑了小于零)
dis_buf[5]=t_uint/100;
dis_buf[6]=t_uint/10%10;
}
else{
dis_buf[6]=t_uint/10;
if(sign==1){dis_buf[5]=11;}
}
dis_buf[7]=t_uint%10;
}
else if(dis_mode==1){//时间显示
dis_buf[1]=2;
if(ds_mode==0){
dis_buf[3]=ds_value[0];
dis_buf[4]=ds_value[1];
dis_buf[5]=11;
dis_buf[6]=ds_value[2];
dis_buf[7]=ds_value[3];
}
else if(ds_mode==1){
dis_buf[3]=ds_value[2];
dis_buf[4]=ds_value[3];
dis_buf[5]=11;
dis_buf[6]=ds_value[4];
dis_buf[7]=ds_value[5];
}
}
else if(dis_mode==2){//参数显示
dis_buf[1]=3;
tem_para>=10?(dis_buf[6]=tem_para/10):(dis_buf[6]=12);
dis_buf[7]=tem_para%10;
}
}
void init(){
cls_buzz();
set_resolution(0x5f);
init_ds1302();
TMOD=0x01;
TL0=0x18;
TH0=0xfc;
ET0=1;
EA=1;
TR0=1;
}
void cls_buzz(){
P0=0x00;
P2=(P2&0x1f)|0xa0;
P2&=0x1f;
}
void display(){
uchar dis_out;
P0=0xff;
P2=(P2&0x1f)|0xe0;
P2&=0x1f;
P0=1<<dis_com;
P2=(P2&0x1f)|0xc0;
P2&=0x1f;
dis_out=dis_code[dis_buf[dis_com]];
if(dis_mode==0&&dis_com==6&&dis_buf[6]!=12){
dis_out&=0x7f;
}
P0=dis_out;
P2=(P2&0x1f)|0xe0;
P2&=0x1f;
P0=0x00;
if(++dis_com==8){dis_com=0;}
}
void scan_key(){
uchar key=0,row=0,col=0;
switch(key_state){
case 0:{
P3=0x0f;
P42=0;P44=0;
if(P3!=0x0f){
key_state=1;
}
}
break;
case 1:{//按键持续按下
P3=0x0f;
P42=0;P44=0;
key=P3&0x0f;
if(key==0x0f){
key_state=0;
return;
}
if(key==0x0b){row=2;}
else if(key==0x07){row=3;}
else{//按下的按键在第一二排
key_state=2;
return;
}
P3=0xf0;
P42=1;P44=1;
if(P34==0){col=2;}
else if(P35==0){col=3;}
else {//按下的按键在第一二列
key_state=2;
return;
}
key=row*4+col;
if(key==10){//S17 减少参数值和输出秒
if(dis_mode==1){//数字显示界面按下
ds_mode=1;//切换为分秒显示
}
else if(dis_mode==2){//参数界面
if(tem_para>10){
tem_para--;
dis_change();
}
}
}
else if(key==11){//S13 切换控制模式
re_mode=~re_mode;
if(re_mode==1&&ds_int==0){//如果当前继电器为闭合状态且切换到时钟控制模式应关闭则利用re()函数里面的判断,赋re_cnt1=20关闭继电器
re_cnt1=20;
}
}
else if(key==14){//S16 增加参数值
if(dis_mode==2){
if(tem_para<99){
tem_para++;
dis_change();
}
}
}
else if(key==15){//S12 切换显示模式
if(dis_mode==0){
dis_mode=1;
}
else if(dis_mode==1){
dis_mode=2;
}
else if(dis_mode==2){
dis_mode=0;
}
dis_change();
}
key_state=2;
}
break;
case 2:{
P3=0x0f;
P42=0;P44=0;
if(P3==0x0f){
ds_mode=0;
key_state=0;
}
}
break;
}
}
void led(){
static uchar led_out=0xff;
if(ds_int==1){//分秒位均为0说明是整点
L1_flag=1;
led_out&=0xfe;//开启L1
}
if(L1_cnt1>=20){
L1_flag=0;
L1_cnt1=0;
led_out|=0x01;//关闭L1
}
if(re_mode==0){
led_out&=0xfd;//开启L2
}
else{
led_out|=0x02;//关闭L2
}
if(L3_state==1){
led_out&=0xfb;//开启L3
}
else{
led_out|=0x04;//关闭L3
}
P0=led_out;
P2=(P2&0x1f)|0x80;
P2&=0x1f;
}
void re(){
static uchar re_out=0x00;
if(re_mode==0){//温度控制模式
if(tem_value-tem_para>0){
re_out=0x10;
L3_flag=1;
}
else{
re_out=0x00;
L3_flag=0;
L3_state=0;
}
}
else if(re_mode==1){//时间控制模式
if(ds_int==1){
re_out=0x10;
re_flag=1;
L3_flag=1;
}
else{
if(re_cnt1>=20){
re_out=0x00;
re_cnt1=0;
L3_flag=0;
L3_state=0;
}
}
}
P0=re_out;
P2=(P2&0x1f)|0xa0;
P2&=0x1f;
}
onewire.h
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
#include "stc15f2k60s2.h"
#define uchar unsigned char
sbit DQ = P1^4;
float rd_tem(void);
void set_resolution(uchar res);
void tem_start_convert();
#endif
onewire.c
#include "onewire.h"
//单总线内部延时函数
void Delay_OneWire(unsigned int t)
{
uchar i;
while(t--){
for(i=0;i<12;i++);
}
}
//单总线写操作
void write_ds18b20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//单总线读操作
unsigned char read_ds18b20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//DS18B20初始化
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
void set_resolution(uchar res){//0x7f 12 0x5f 11 0x3f 10 0x1f 9这里要求温度刷新时间小于等于1秒钟,那就设置为11位工作方式,最大转换时间为375ms好了
init_ds18b20();
write_ds18b20(0xcc);
write_ds18b20(0x4e);
write_ds18b20(0x7f);
write_ds18b20(0x00);
write_ds18b20(res);
init_ds18b20();
write_ds18b20(0xcc);
write_ds18b20(0x48);
}
void tem_start_convert(){
init_ds18b20();
write_ds18b20(0xcc);
write_ds18b20(0x44);
}
float rd_tem(){
uchar low,high;
float out;
init_ds18b20();
write_ds18b20(0xcc);
write_ds18b20(0xbe);
low=read_ds18b20();
high=read_ds18b20();
if(high>>4){//负数
out=low+high*256;
out=(4096-(out/16))*(-1);
}
else {
out=low+high*256;
out/=16;
}
return out;
}
ds1302.h
#ifndef __DS1302_H
#define __DS1302_H
#include <stc15f2k60s2.h>
#include <intrins.h>
#define uchar unsigned char
sbit SCK = P1^7;
sbit SDA = P2^3;
sbit RST = P1^3;
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
void init_ds1302();
uchar* read_ds1302();
#endif
ds1302.c
#include "ds1302.h"
//写字节
void write_ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
}
}
//向DS1302寄存器写入数据
void write_ds1302_byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
write_ds1302(address);
write_ds1302(dat);
RST=0;
}
//从DS1302寄存器读出数据
unsigned char read_ds1302_byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
write_ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
void init_ds1302(){
write_ds1302_byte(0x8e,0x00);//关闭写入保护
write_ds1302_byte(0x80,0x50);//秒
write_ds1302_byte(0x82,0x59);//分
write_ds1302_byte(0x84,0x22);//时
write_ds1302_byte(0x8e,0x80);//开启写入保护
}
uchar* read_ds1302(){
static uchar time[6];
uchar t_time[3];
t_time[0]=read_ds1302_byte(0x81);
t_time[1]=read_ds1302_byte(0x83);
t_time[2]=read_ds1302_byte(0x85);
time[0]=t_time[2]>>4;
time[1]=t_time[2]&0x0f;
time[2]=t_time[1]>>4;
time[3]=t_time[1]&0x0f;
time[4]=t_time[0]>>4;
time[5]=t_time[0]&0x0f;
return time;
}
个人水平较低,如发现问题请予以告知,谢谢!
版权声明:本文为qq_39384136原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。