【蓝桥杯单片机】蓝桥杯单片机第十一届省赛程序设计题及其详细题解

试题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
    本届赛题没有什么太偏的知识点,主要还是三大件LED、数码管、按键与其他几个常用模块IIC模块与eeprom模块。

程序代码

main.c

#include <config.h>

unsigned int count = 0,count_L1 = 0;
extern unsigned char mod12,V_count,segtab[],L1_flag,L3_flag;//界面切换  采集电压 计数电压
extern unsigned int VV,k_VV;
void main(){
	unsigned char key_num = 20;
	sysinit();
	Timer1Init();
	k_VV = read_eeprom();
	while(1){
		key_num = scankbd();
		switch(key_num){
			case 	8://S12 界面切换
				if(++mod12 == 3) mod12 = 0;L3_flag= 0;
				break;
			case 9://S13  将计数值清零
				if(mod12 == 2) {V_count = 0;L3_flag = 0;}
				break;
			case 12://S16  参数加
				if(mod12 == 1){ 
					k_VV += 5;
					if(k_VV>50) k_VV = 0;
					wire_eeprom(k_VV);
					L3_flag = 0;
				}else{
					L3_flag++;
				}
				break;
			case 13://S17  参数减
				if(mod12 == 1){
					k_VV -= 5;
					if(k_VV>50) k_VV = 50;
					wire_eeprom(k_VV);
					L3_flag = 0;
				}else{
					L3_flag++;
				}
				break;
			default: if(key_num != 20) L3_flag++;break;
		}
		if(count%100==0){
			VV = adc(0x43);
			VV = VV*100/51.0;
		}
		S12();
		caozuo();
	}
}

void time1() interrupt 3{
	count++;
	if(count%2 == 0) segs();
	if(count%2 == 1) led();
	if(VV<k_VV*10){
		count_L1++;
		if(count_L1 >= 5000){
			L1_flag = 1;
		}else{
			L1_flag = 0;
		}
	}else{
		count_L1 = 0;
		L1_flag = 0;
	}
}

config.c

#include <config.h>

sbit relay = P0^4;
sbit buzzer = P0^6;
void sysinit(){
	P2 = P2&0x1f|0x80;P0 = 0xff;P2 &= 0x1f;
	P2 = P2&0x1f|0xa0;relay = 0;buzzer = 0;P2 &= 0x1f;
	P2 = P2&0x1f|0xe0;P0 = 0xff;P2 &= 0x1f;
	P2 = P2&0x1f|0xc0;P0 = 0x00;P2 &= 0x1f;
}

#define kbd_io P3
#define kbd_maskrow 0x0f
unsigned char scankbd(){
 	unsigned char key_num = 20;
	static unsigned char kbd_state = 0;
	unsigned char kbd_press;
	switch(kbd_state){
		case 0:
			kbd_io = 0x0f;P44 = 0;P42 = 0;kbd_press = kbd_io;
			if(kbd_press != kbd_maskrow){
				kbd_state = 1;
			}
			break;
		case 1:
			kbd_press = kbd_io;
			if(kbd_press != kbd_maskrow){
				if((kbd_io&0x08)==0) key_num = 0;
				if((kbd_io&0x04)==0) key_num = 1;
				if((kbd_io&0x02)==0) key_num = 2;
				if((kbd_io&0x01)==0) key_num = 3;
				kbd_io = 0xf0;P42 = 1;P44 = 1;
				if(P44 == 0) key_num += 0;
				if(P42 == 0) key_num += 4;
				if((kbd_io&0x20)==0) key_num += 8;
				if((kbd_io&0x10)==0) key_num += 12;
				kbd_state = 2;
			}else{
				kbd_state = 0;
			}
			break;
		case 2:
			kbd_io = 0x0f;P42 = 0;P44 =  0;kbd_press = kbd_io;
			if(kbd_press == kbd_maskrow) kbd_state = 0;
			break;
		default:break;
	}
	return key_num;
}

unsigned char segtab[] = {10,10,10,10,10,10,10,10};
unsigned char segbuff[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,
0xc0&0x7f,0xf9&0x7f,0xa4&0x7f,0xb0&0x7f,0x99&0x7f,0x92&0x7f,0x82&0x7f,0xf8&0x7f,0x80&0x7f,0x90&0x7f,0xbf,0xff,
0xc1,0x8c,0xc8};//U  P  N
	
void segs(){
	static unsigned char segaddr = 0;
	P2 = P2&0x1f|0xe0;P0 = 0xff;P2 &= 0x1f;
	P2 = P2&0x1f|0xc0;P0 = 1<<segaddr;P2 &= 0x1f;
	P2 = P2&0x1f|0xe0;P0 = segbuff[segtab[segaddr]];P2 &= 0x1f;
	if(++segaddr == 8) segaddr = 0;
}

void Timer1Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x18;		//设置定时初始值
	TH1 = 0xFC;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	EA = 1;
	ET1 = 1;
}

unsigned int VV =0,k_VV = 0;//采集电压
unsigned char mod12 = 0,V_count = 0;//界面切换   计数电压
void S12(){
	switch(mod12){
		case 0://电压显示
			segtab[0] = 24;//U
			segtab[1] = 10;
			segtab[2] = 10;
			segtab[3] = 10;
			segtab[4] = 10;
			segtab[5] = VV/100+12;
			segtab[6] = VV/10%10;
			segtab[7] = VV%10;
			break;
		case 1://电压参数显示
			segtab[0] = 25;//P
			segtab[1] = 10;
			segtab[2] = 10;
			segtab[3] = 10;
			segtab[4] = 10;
			segtab[5] = k_VV/10+12;
			segtab[6] = k_VV%10;
			segtab[7] = 0;
			break;
		case 2://计数显示
			segtab[0] = 26;//N
			segtab[1] = 10;
			segtab[2] = 10;
			segtab[3] = 10;
			segtab[4] = 10;
			segtab[5] = 10;
			segtab[6] = V_count/10;
			segtab[7] = V_count%10;
			break;
	}
}

sbit L1 = P0^0;
sbit L2 = P0^1;
sbit L3 = P0^2;
unsigned char L1_flag = 0,L3_flag = 0;
void led(){
	P2 = P2&0x1f|0x80;P0 = 0xff;P2 &= 0x1f;
	if(L1_flag == 1){
		P2 = P2&0x1f|0x80;L1 = 0;P2 &= 0x1f;
	}else{
		P2 = P2&0x1f|0x80;L1 = 1;P2 &= 0x1f;
	}
	if(V_count%2 == 1){
		P2 = P2&0x1f|0x80;L2 = 0;P2 &= 0x1f;
	}else{
		P2 = P2&0x1f|0x80;L2 = 1;P2 &= 0x1f;
	}
	if(L3_flag>=3){
		P2 = P2&0x1f|0x80;L3 = 0;P2 &= 0x1f;
	}else{
		P2 = P2&0x1f|0x80;L3 = 1;P2 &= 0x1f;
	}
}

unsigned int old = 0;//储存上一次的电压值
void caozuo(){
	static unsigned char flag = 0;//判断上一次电压值是否大于电压参数
	if(old > k_VV*10){
		flag = 1;
	}else{
		flag = 0;
	}
	
	if(VV < k_VV*10 && flag == 1){
		V_count++;
	}
	old = VV;
}

iic.c

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "iic.h"
#include "STC15F2K60S2.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
	IIC_Delay(DELAY_TIME);
	da <<= 1;
	if(SDA) da |= 1;
	SCL = 0;
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}
void wire_eeprom(unsigned char date){
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(0x00);
	IIC_WaitAck();
	
	IIC_SendByte(date);
	IIC_WaitAck();
	IIC_Stop();
}
unsigned char read_eeprom(){
	unsigned char date = 0;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(0x00);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0xa1);
	IIC_WaitAck();
	date = IIC_RecByte();
	IIC_SendAck(0);
	IIC_Stop();
	
	return date;
}
unsigned char adc(unsigned char add){
	unsigned char date = 0;
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	date = IIC_RecByte();
	IIC_SendAck(1); 
	IIC_Stop();
	
	return date;
}

coonfig.h

#ifndef __CONFIG_H
#define __CONFIG_H

#include <STC15F2K60S2.h>
#include "iic.h"

void sysinit();
unsigned char scankbd();
void segs();
void Timer1Init(void);	//1毫秒@12.000MHz
void S12();
void led();
void caozuo();

#endif

iic.h

#ifndef _IIC_H
#define _IIC_H

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 

void wire_eeprom(unsigned char date);
unsigned char read_eeprom();
unsigned char adc(unsigned char add);

#endif

个人感悟

1.不管是写省赛试题也好,写国赛试题也罢,首先一点就是要看清楚题目,明白题目的意思并写出相应的功能。当然了,我们在写程序时,还需要注意试题上给出的初试状态。一般所涉及到的各个模块都会给出一两个初始值,假如不注意,这里也会扣一点分。
2.在本届是试题中,小编个人认为最不好处理的还是计数值如何加1。这里需要注意的是,当采集到的电压先大于电压参数后小于电压参数时,计数值才加1。

  • 6
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值