蓝桥杯资料包
源码
强烈建议先自己做一遍,这是蓝桥杯单片机最简单的一道题。
首先从试题的系统框图开始看
如图所示,有AD转换,所以IIC肯定是需要用的
有数码管,所以数码管先写上
有按键,但确定是独立按键还是矩阵按键,往下翻
S5,S7所以使用独立按键就行
所以,我们先建立工程,然后把需要的数码管,IIC,独立按键先添加进去并且调试好。
main.c
#include
#include "intrins.h"
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int
void SMG_output(void);
void init(void);
void Delay1ms(void);
void delay5ms(void);
void Dkey_scan(void);
uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf};
uchar SMG[8]={20,20,20,20,20,20,20,20};//初始显示10,全息数码管
void main(void)
{
init();
while(1)
{
SMG_output();
Dkey_scan();
}
}
void Dkey_scan(void) //矩阵按键
{
static uchar keybyte=0;
static uchar key;
if(((P3&0X0F)!=0X0F)&&(keybyte==0))
{
delay5ms();
if((P3&0X0F)!=0X0F)
{
keybyte=1;key=P3&0x0f;
}
}
if((keybyte==1)&&((P3&0X0F)==0X0F))
{
if((P3&0X0F)==0X0F)
{
switch(key)
{
case 0x0e:SMG[0]=1;
break;
case 0x0d:SMG[1]=1;
break;
case 0x0b:SMG[2]=1;
break;
case 0x07:SMG[3]=1;
break;
}
keybyte=0;
}
}
}
void SMG_output(void) //数码管显示函数
{
uchar i;
for(i=0;i<8;i++)
{
P2=(P2&0X1F)|0Xc0;
P0=(1<<i);
P2=(P2&0X1F)|0Xe0;
P0=tab[SMG[i]];
Delay1ms();
}
P2=(P2&0X1F)|0Xc0;
P0=0Xff;
P2=(P2&0X1F)|0Xe0;
P0=0Xff;
}
void init(void) //初始化函数,关闭所有外设
{
P2=(P2&0X1F)|0XA0;
P0=0X00;
P2=(P2&0X1F)|0X80;
P0=0Xff;
P2=(P2&0X1F)|0Xc0;
P0=0Xff;
P2=(P2&0X1F)|0Xe0;
P0=0Xff;
}
void Delay1ms(void) //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void delay5ms(void) //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
iic.c
#include "iic.h"
#define DELAY_TIME 40
//IIC的读函数,参数(硬件地址,寄存器地址,数据)
void IIC_write(uchar hw_address,uchar reg_address,uchar num)
{
IIC_Start();
IIC_SendByte(hw_address&0xfe);
IIC_WaitAck();
IIC_SendByte(reg_address);
IIC_WaitAck();
IIC_SendByte(num);
IIC_WaitAck();
IIC_Stop();
}
//IIC读函数 参数:硬件地址,寄存器地址
uchar IIC_read(uchar hw_address,uchar reg_address)
{
uchar num;
IIC_Start();
IIC_SendByte(hw_address&0xfe);
IIC_WaitAck();
IIC_SendByte(reg_address);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(hw_address|0x01);
IIC_WaitAck();
num=IIC_RecByte();
IIC_WaitAck();
IIC_Stop();
return num;
}
//
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;
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;
}
//
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;
}
//
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;
}
iic.h
#ifndef _IIC_H
#define _IIC_H
#include "stc15f2k60s2.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
sbit SDA = P2^1;
sbit SCL = P2^0;
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);
uchar IIC_read(uchar hw_address,uchar reg_address);
void IIC_write(uchar hw_address,uchar reg_address,uchar num);
#endif
然后编译,会发现有几个警告,*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
,像这中警告一般是有函数没有调用,不用理会,直接下载调试。效果应该是按下按键,数码管对应亮一。
然后接着往下看题目。
数码管显示有两种状态,所以肯定是要定义一,个变量用于切换状态的。定义好后,首先按照如图数码管一模一样显示出来,定义一个价格变量price=50,50方便显示
;定义一个总价all_price=50
,然后显示出来。改变之后的代码如下:
uchar SMG_mode=0; //数码管切换状态变量
uchar price=50; //价格变量
uint all_price=50,water_num=100; //总价变量 //出水量定义
void main(void)
{
init();
while(1)
{
if(SMG_mode==0) //数码管模式一 售水机出水状态数码管显示
{//加上10都是为了显示小数点
SMG[0]=20;SMG[1]=price/100+10;SMG[2]=price%100/10;
SMG[3]=price%10;SMG[4]=water_num/1000;
SMG[5]=water_num%1000/100+10;
SMG[6]=water_num%100/10;SMG[7]=water_num%10;
}
else if(SMG_mode==1) //数码管模式二 售水机出停水态数码管显示
{//加上10都是为了显示小数点
SMG[0]=20;SMG[1]=price/100+10;SMG[2]=price%100/10;
SMG[3]=price%10;SMG[4]=all_price/1000;
SMG[5]=all_price%1000/100+10;
SMG[6]=all_price%100/10;SMG[7]=all_price%10;
}
SMG_output();
Dkey_scan();
}
}
如题
然后数码管需要由按键控制,所以在按键中在增加相应控制程序(S7显示数码管模式一,并且继电器接通,L10亮,S6显示数码管模式二,并且继电器断开,L10熄灭),由于只需要S7和S6,所以把独立按键另外两个按键删除。
对应独立按键修改的程序为:
void Dkey_scan(void)
{
static uchar keybyte=0;
static uchar key;
if(((P3&0X0F)!=0X0F)&&(keybyte==0))
{
delay5ms();
if((P3&0X0F)!=0X0F)
{
keybyte=1;key=P3&0x0f;
}
}
if((keybyte==1)&&((P3&0X0F)==0X0F))
{
if((P3&0X0F)==0X0F)
{
switch(key)
{
case 0x0e:
if(SMG_mode==1)SMG_mode=0; //切换数码管模式
P2=0XA0;P0=0X10; //点亮L10,接通继电器
break;
case 0x0d:
if(SMG_mode==0)SMG_mode=1;
P2=0XA0;P0=0X00; //熄灭L10,关闭继电器
break;
}
keybyte=0;
}
}
}
记得下载调试!!!
然后接着看试题
由于要使用AD转换,所以要使用IIC了,首先看要求是PCF8591读取光敏电阻的电压,所以IIC读的硬件地址0x90
,然后光敏电阻地址为0x01
,然后输入电压小于1.25V,L1点亮,否则L1熄灭,所以首先要将读取的值转换为电压值,即255转换为5V,然后再进行判断就行。
所以主函数变为:
uchar light=0;
void main(void)
{
init();
while(1)
{
light=IIC_read(0x90,0x01); //读取光敏电阻阻值
light=light*1.9607; //500/255 放大100倍
if(light<125) //判断条件
{
P2=0X80;P0=0XFE; //打开L1;
}
else if(light>125)
{
P2=0X80;P0=0XFF; //关闭L1;
}
然后下载调试,发现遮住光敏电阻L1点亮。
然后再看最后一个要求:
计算价格,并且给出出水量限额,100毫升/秒就是0.1升/秒,所以首先要使用定时器来计时出水。
更改代码如下:
定时器出水
void time0() interrupt 1
{
t++;
if(t==1000) //1ms计时1000次==1s
{
t=0;
if(SMG_mode==0) //数码管模式0才加水 即出水模式才加水
water_num+=10; //每一秒出水
}
}
按键计算价格和清零
case 0x0e:
if(SMG_mode==1){SMG_mode=0;water_num=0;}//切换数码管模式,出水量清零
P2=0XA0;P0=0X10; //点亮L10,接通继电器
break;
case 0x0d:
if(SMG_mode==0)SMG_mode=1;
P2=0XA0;P0=0X00; //熄灭L10,关闭继电器
all_price=((water_num*price)/100); //计算价格
break;
出水限制
if(water_num>9999)
{
SMG_mode=1;P2=0XA0;P0=0X00; //熄灭L10,关闭继电器
all_price=((water_num*price)/100); //计算价格
}
最后别忘记更改初始出水量和价格,删除没用的函数。
完整代码:
#include
#include "intrins.h"
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int
void SMG_output(void);
void init(void);
void Delay1ms(void);
void delay5ms(void);
void Dkey_scan(void);
void Timer0Init(void);
uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf};
uchar SMG[8]={20,20,20,20,20,20,20,20};//初始显示10,全息数码管
uchar SMG_mode=0; //数码管切换状态变量
uchar price=50; //价格变量
uint all_price=0,water_num=0; //总价变量 //出水量定义
uint light=0;
uint t=0; //定时器变量
void main(void)
{
init(); //初始开发板
Timer0Init(); //初始化定时器
while(1)
{
light=IIC_read(0x90,0x01); //读取光敏电阻阻值
light=light*1.9607; //500/255 放大100倍
if(light<125) //判断条件
{
P2=0X80;P0=0XFE; //打开L1;
}
else if(light>125)
{
P2=0X80;P0=0XFF; //关闭L1;
}
if(SMG_mode==0) //数码管模式一 售水机出水状态数码管显示
{//加上10都是为了显示小数点
SMG[0]=20;SMG[1]=price/100+10;SMG[2]=price%100/10;
SMG[3]=price%10;SMG[4]=water_num/1000;
SMG[5]=water_num%1000/100+10;
SMG[6]=water_num%100/10;SMG[7]=water_num%10;
}
else if(SMG_mode==1) //数码管模式二 售水机出停水态数码管显示
{//加上10都是为了显示小数点
SMG[0]=20;SMG[1]=price/100+10;SMG[2]=price%100/10;
SMG[3]=price%10;SMG[4]=all_price/1000;
SMG[5]=all_price%1000/100+10;
SMG[6]=all_price%100/10;SMG[7]=all_price%10;
}
if(water_num>9999)
{
SMG_mode=1;P2=0XA0;P0=0X00; //熄灭L10,关闭继电器
all_price=((water_num*price)/100); //计算价格
}
SMG_output();
Dkey_scan();
}
}
void Dkey_scan(void)
{
static uchar keybyte=0;
static uchar key;
if(((P3&0X0F)!=0X0F)&&(keybyte==0))
{
delay5ms();
if((P3&0X0F)!=0X0F)
{
keybyte=1;key=P3&0x0f;
}
}
if((keybyte==1)&&((P3&0X0F)==0X0F))
{
if((P3&0X0F)==0X0F)
{
switch(key)
{
case 0x0e:
if(SMG_mode==1){SMG_mode=0;water_num=0;}//切换数码管模式,出水量清零
P2=0XA0;P0=0X10; //点亮L10,接通继电器
break;
case 0x0d:
if(SMG_mode==0)SMG_mode=1;
P2=0XA0;P0=0X00; //熄灭L10,关闭继电器
all_price=((water_num*price)/100); //计算价格
break;
}
keybyte=0;
}
}
}
void time0() interrupt 1
{
t++;
if(t==1000) //1ms计时1000次==1s
{
t=0;
if(SMG_mode==0) //数码管模式0才加水 即出水模式才加水
water_num+=10; //每一秒出水
}
}
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;ET0=1; //打开中断
}
void SMG_output(void)
{
uchar i;
for(i=0;i<8;i++)
{
P2=(P2&0X1F)|0Xc0;
P0=(1<<i);
P2=(P2&0X1F)|0Xe0;
P0=tab[SMG[i]];
Delay1ms();
}
P2=(P2&0X1F)|0Xc0;
P0=0Xff;
P2=(P2&0X1F)|0Xe0;
P0=0Xff;
}
void init(void)
{
P2=(P2&0X1F)|0XA0;
P0=0X00;
P2=(P2&0X1F)|0X80;
P0=0Xff;
P2=(P2&0X1F)|0Xc0;
P0=0Xff;
P2=(P2&0X1F)|0Xe0;
P0=0Xff;
}
void Delay1ms(void) //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void delay5ms(void) //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
最后演示视频
最后可以有问题可以私信和评论。