蓝桥杯单片机组备赛指南请查看这篇文章:戳此跳转蓝桥杯备赛指南文章
本文章针对蓝桥杯-单片机组比赛开发板所写,代码可直接在比赛开发板上使用。
型号:国信天长4T开发板(绿板),芯片:IAP15F2K61S2
(使用国信天长蓝板也可以完美兼容,与绿板几乎无差别)
1.存储器映射拓展
(截取自小蜜蜂单片机课程视频)
存储器映射拓展方式的地址:
0x8000 | 指示灯 |
0xa000 | 蜂鸣器与继电器 |
0xc000 | 数码管位选 |
0xe000 | 数码管段选 |
在比赛当中,建议还是只使用IO口拓展方式,尽量不使用存储器映射拓展方式。
注意:
进行存储器映射拓展时,需要将开发板J13的跳线帽连接到“MM模式”
使用XBYTE关键字,需要引入头文件“ absacc.h ”来操作拓展资源
存储器拓展方式要占用单片机的P3.6引脚,会与矩阵键盘的引脚冲突
1.1 代码参考
在主函数中进行选择,对state_all赋不同初值,获得不同的效果。
1——蜂鸣器与数码管;2——蜂鸣器单独作用;3——数码管单独作用(默认)
#include < reg52.h >
#include < intrins.h >
#include < absacc.h >
//使用定时器1实现延时效果
//使用四个独立按键实现类型选择
unsigned char code SMG_duanma [18]=
{ 0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 ,
0x80 , 0x90 , 0x88 , 0x80 , 0xc6 , 0xc0 , 0x86 , 0x8e ,
0xbf , 0x7f };
void Delay ( unsigned char time )
{
unsigned char i,j;
if ( time%2 == 0 )
{
time /= 2;
}
else
{
time = (time/=2) + 1;
}
while ( time-- )
{
_nop_ ();
_nop_ ();
i=22;
j=128;
do
{
while ( --j );
}
while ( --i );
}
}
void ledrunning ( unsigned char linspace )
{
unsigned char i,state_led;
for ( i=0 ; i<8 ; i+=linspace )
{
state_led = 0xff;
state_led &= ~( 1<<i );
XBYTE[0x8000] = state_led;
Delay (500);
}
}
void buzzrunning ( unsigned char buzz_state )
{
if ( buzz_state == 0 )
XBYTE[0xa000] = 0x00;
else
XBYTE[0xa000] = 0xff;
}
void SMG_running ( )
{
unsigned char i,j;
for ( i=0 ; i<7 ; i++ )
{
XBYTE[0xc000] = 0x01 << i;
for ( j=0 ; j<10 ; j++ )
{
XBYTE[0xe000] = SMG_duanma [j];
Delay (500);
}
}
}
void main ()
{
unsigned char state_all = 3;
while (1)
{
if ( state_all == 1 )
{
buzzrunning (0);
ledrunning (1);
}
else if ( state_all == 2 )
{
buzzrunning (0);
Delay ( 400 );
buzzrunning (1);
Delay ( 400 );
}
else if ( state_all == 3 )
{
buzzrunning (0);
SMG_running ();
}
}
}
2.PWM脉冲宽度调制
2.1 pwm脉冲调制的作用效果
比较通俗的来说,pwm脉冲调制,可以让我们自定义灯光的亮度,使得LED灯可以产生不同的亮度;自定义电机的转速,使得电机可以以不同的速度旋转;自定义蜂鸣器的嗡叫大小,使得蜂鸣器也可以小声歌唱……
比较专业的来说则是:脉冲宽度调制PWM是通过将有效的电信号分散成离散形式从而来降低电信号所传递的平均功率的一种方式。所以根据面积等效法则,可以通过对改变脉冲的时间宽度,来等效的获得所需要合成的相应幅值和频率的波形,实现模拟电路的数字化控制。PWM信号是通过调节占空比的变化来调节信号、能量等的变化。
2.2 什么是PWM
PWM(Pulse-width modulation),中文名脉冲宽度调制。下面我采用功率的思路来理解PWM的作用。
在我们之前的编程中,单片机的引脚通过赋值1或0,从而输出5v或0v的电压。如下图所示:
在1个周期中,可以看出单片机引脚的输出电压恒定为5v,假设引脚上接了一个5欧姆的电阻,则该电阻获得的功率是恒定的,W=U^2/R=5^2/5=5瓦特。如果我们希望电阻上的功率低一些怎么办?根据W=Q/t式子,分子Q与电压直接相关,而电压由硬件电路决定无法改变;分母t与我们使单片机引脚为高电平的时间有关,可以通过编程更改。因此,我们可以设置在一个周期中,单片机引脚处于高电平的时长,从而改变输出功率,让电阻的功率降低。
假设我们要使电阻上的功率为3w,由面积等效规律可得出,在一个周期中高电平应该占据60%的时长,画出电压图像为:
通过设置在一个周期中,高电平与低电平所占时长的比例,即可实现0~最大功率之间的功率输出。其中,高电平所占的时长我们称为占空比(Duty cycle),通常规定其数值为0~100%,当占空比为100%时即表示最大功率输出。
2.3 pwm的编程原理
在编程时,我们可以利用定时/计数器生成一个100个时钟序列的周期,在时钟序列累加值低于占空比数值时输出高电平,时钟序列累加值高于占空比数值时输出低电平,从而实现一个周期中的脉冲宽度调制。
我们定义两个变量,pwm_count和pwm_duty:
pwm_count 变量用于计数一个周期中的时钟序列个数。采用定时/计数器中断设置时钟序列间隔,通常可以设置为0.1ms,每经历一次0.1ms,通过中断使该变量自增1 。因为占空比在0~100之间变化,为了方便我们也设置该变量在计数值达到100时清零。
pwm_duty变量用于定义占空比。在编写函数时,当pwm_count<pwm_duty时,我们令引脚输出高电平,反之输出低电平。在调用函数时,通过向函数中传递0~100以内的数值,从而设置引脚输出功率在最大功率的0~100%之间变化。
2.4 pwm的代码参考
代码效果://按键S7通过控制pwm来控制LED1的亮度
//按键S7通过控制pwm来控制LED1的亮度
#include < REGX52.h >
#include < INTRINS.h >
sbit S7 = P3^0;
sbit L1 = P0^0;
void select_HC573 ( unsigned char channal )
{
switch ( channal )
{
case 4:
P2 = ( P2 & 0x1f ) | 0x80;
break;
case 5:
P2 = ( P2 & 0x1f ) | 0xa0;
break;
case 6:
P2 = ( P2 & 0x1f ) | 0xc0;
break;
case 7:
P2 = ( P2 & 0x1f ) | 0xe0;
break;
}
}
void Delay ( unsigned char value_delay )
{
while ( value_delay -- )
{
unsigned char i,j;
_nop_ ();
_nop_ ();
i = 22;
j = 128;
do
{
while ( --j );
}while ( --i );
}
}
unsigned char key_value = 1;
void scan_key ()
{
if ( S7 == 0 )
{
Delay ( 3 );
if ( S7 == 0 )
{
while ( S7 == 0 );
key_value ++ ;
if ( key_value == 5 )
{
key_value = 1;
}
}
}
}
//=============================================
void Init_Timer0 ()
{
TMOD = 0x01;
TH0 = ( 65535 - 100 ) / 256;
TL0 = ( 65535 - 100 ) % 256;
ET0 = 1;
EA = 1;
TR0 = 1;
}
unsigned char pwm_count = 0;
void Service_Timer0 () interrupt 1
{
TH0 = ( 65535 - 100 ) / 256;
TL0 = ( 65535 - 100 ) % 256;
pwm_count++;
}
//===============================================
void set_pwm ( unsigned char duty_pwm )
{
if ( pwm_count <= duty_pwm )
{
L1 = 0;
}
else if ( pwm_count < 100 )
{
L1 = 1;
}
else if ( pwm_count == 100 )
{
pwm_count = 0;
}
}
void L1_pwmrunning ()
{
switch ( key_value )
{
case 1:
TR0 = 0;
L1 = 1;
break;
case 2:
TR0 = 1;
set_pwm ( 10 );
break;
case 3:
// TR0 = 1;
set_pwm ( 50 );
break;
case 4:
// TR0 = 1;
set_pwm ( 90 );
break;
}
}
void main ()
{
select_HC573 ( 4 );
Init_Timer0 ();
while ( 1 )
{
scan_key ();
L1_pwmrunning ();
}
}
3.PWM脉冲宽度调制编程思路重述
通过定时/计数器设置100个时钟序列,通过计数时钟序列,并于占空比进行比较确定输出高电平或者低电平。到计数值小于占空比时输出高电平,大于占空比时输出低电平。