基于Proteus中的STC15W4K32S4编写的流⽔灯程序(c语
⾔)——其⼀
⽬录
⼀、简介
本实验基于STC15开发板上实施,硬件电路包括STC单⽚机与PC机USB接⼝的通信线路,以及LED4、LED7、LED8、LED9、LED10等LED灯,对应STC的P2.7,P1.7,P1.6,P4.7,P4.6。基于Proteus中的STC15W4K32S4编写的程序,实验要求:要求
LED4(P2.7)、LED10(P4.6)、LED9(P4.7)、LED8(P1.6)、LED7(P1.7)按顺序每隔1S依次闪烁,按下SW17(接P3.2)时,灯停⽌闪烁。
本系列⽂章共有三篇,区别为按键和延时实现的⽅式(查询or中断)。⽂章发布从逻辑上由简⾄难,本篇为⽤查询实现的按键功能和⽤查询实现的延时功能。
⼆、电路原理图
三、程序源代码
#include<stc15.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit LED4=P2^7;
sbit LED10=P4^6;
sbit LED9=P4^7;
sbit LED8=P1^6;
sbit LED7=P1^7;
sbit LED7=P1^7;
sbit SW17=P3^2;
uint b=1;
uint flag=1;
/*按键防抖函数*/
void delayms(uint n)
{
while(n--);
}
/*开关函数*/
void key()
{
if(SW17==0)
{
flag=SW17;
delayms(100);
if(SW17==0)
{
LED4=LED10=LED9=LED8=LED7=1;    b=0;
}
}
}
/*灯延迟函数*/
void delay()    //1s延时
{
uchar i,j,k,m;
for(i=5;i>0;i--)
for(j=68;j>0;j--)
for(k=22;k>0;k--)
for(m=94;m>0;m--)
key();
}
/*亮灯函数*/
void LED()
{
if(flag==1)
{
switch(b)
{
case 1: LED4=0;break;
case 2: LED4=1;LED10=0;break;    case 3: LED10=1;LED9=0;break;
case 4: LED9=1;LED8=0;break;
case 5: LED8=1;LED7=0;break;
default:LED7=1;LED4=0;b=1;break;    }
delay();
b++;
}
}
/*主函数*/
void main()
{
P0M0=0;    //定义I/O⼝⼯作模式
P0M1=0;
P1M0=0;
P1M1=0;
P2M0=0;
P2M1=0;
P3M0=0;
P3M1=0;
P4M0=0;
P4M1=0;
while(1)
{
{
LED();
}
}
四、程序分析
1.头⽂件、宏定义
本实验代码段未⽤到<intrins.h>⽂件内函数,也可不加此⾏。
#include<stc15.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
2.管脚定义,变量声明
sbit LED4=P2^7;
sbit LED10=P4^6;
sbit LED9=P4^7;
sbit LED8=P1^6;
sbit LED7=P1^7;
sbit SW17=P3^2;
uint b=1;
uint flag=1;
3.按键防抖函数
因为本实验开发板⽤的为按钮式开关,当机械触点断开、闭合时,由于机械触点的弹性作⽤,⼀个按键开关在闭合时不会马上就稳定地接通,在断开时也不会⼀下⼦彻底断开,⽽是在闭合和断开的瞬间伴随了⼀连串的抖动按键 。抖动时间是由按键的机械特性决定的,⼀般都会在10ms以下,为了确保程序对按键的⼀次闭合或者⼀次断开只响应 ⼀次, 必须进⾏按键的消抖处理。
本实验使⽤软件消抖。软件消抖就是当检测到按键状态变化后,先等待⼀个10ms左右的延时,让抖动消失后再进⾏⼀次按键状态检测, 如果与刚才检测到的状态相同,就可以确认按键已经稳定地动作了。这个10ms的延时就是通过让单⽚机执⾏函数中的⼀段程序循环实现,接下来的1s延时也是同理。
/*按键防抖函数*/
void delayms(uint n)
{
while(n--);
}
4.开关函数
当运⾏到开关函数时,先⽤if查询⼀次开关状态,如果闭合(SW17==0),则清零标志位,并延时防抖,当抖动结束后再查询⼀次,如果闭合,则令所有灯置1(灭)。b=0意义为流⽔灯循环从头开始,因为本实验开关只起到了关的作⽤,⽆影响,可不写。
/*开关函数*/
void key()
{
if(SW17==0)
{
flag=SW17;
delayms(100);
if(SW17==0)
{
LED4=LED10=LED9=LED8=LED7=1;
b=0;
}
}
}
5.延迟1s函数
本地⽅着重讲解1s实现原理,因为要求1s精确到0.999999,所以必须将c语⾔反汇编成汇编语⾔从⽽精确计算1s。本地⽅也是笔者实验中遇到的问题所在,经查阅资料慢慢解决。
转为汇编语⾔如下:
C:0x0122    790D    MOV      R1,#0x05        //这四条MOV指令每条占2个系统时钟数
C:0x0124    7D1D    MOV      R5,#0x44
C:0x0126    7B18    MOV      R3,#0x16
C:0x0128    7A6E    MOV      R2,#0x5E
C:0x012A    1200E0  LCALL    key(C:00E0)        //⼦程序调⽤指令,占4个系统时钟数,请注意,调⽤⼦程序后,⼦程序中还有⼀条JB指令(5)和⼦程序返回RET指令(4),所以本⾏程序共占13个系统时钟数
C:0x012D    DAFB    DJNZ    R2,C:012A    //这四条DJNZ指令每条占4个系统时钟数
C:0x012F    DBF7    DJNZ    R3,C:0128
C:0x0131    DDF3    DJNZ    R5,C:0126
C:0x0133    D9EF    DJNZ    R1,C:0124
C:0x0135    22      RET
内层循环:⼦程序调⽤+DJNZ*循环次数
⼆层循环:(内层循环+DJNZ+MOV)*循环次数
三层循环:[(内层循环+DJNZ+MOV)*循环次数+6]*循环次数
......
总系统时钟数为第⼀条mov指令加循环循体时钟数加上延时程序调⽤及返回时钟数
总系统时钟数=2+4+{[ ( ( (4+5+4)+4)*m+6)k+6]j+6}i+4=12,000,000
因为本实验单⽚机晶振为12MHz,所以时钟周期是 1/12M,则为1s。
/
*灯延迟函数*/
void delay()    //1s延时
{
uchar i,j,k,m;
for(i=5;i>0;i--)
for(j=68;j>0;j--)
for(k=22;k>0;k--)
for(m=94;m>0;m--)
key();
}
6.流⽔灯实现程序
4k电影源代码
flag==1判断按键是否有按下,如果按下flag在按键程序被清零,从⽽⽆法进⼊流⽔灯循环程序,实现流⽔灯真正的停⽌。
⽤Switch函数实现循环流⽔,b初值为1,先执⾏case 2,然后break,延时后加1,再次回到函数时执⾏以此类推
/*亮灯函数*/
void LED()
{
if(flag==1)
{
switch(b)
{
case 1: LED4=0;break;
case 2: LED4=1;LED10=0;break;
case 3: LED10=1;LED9=0;break;
case 4: LED9=1;LED8=0;break;
case 5: LED8=1;LED7=0;break;
default:LED7=1;LED4=0;b=1;break;
}
delay();
b++;
}
}
7.主函数
因为使⽤的是15单⽚机,定义I/O⼯作模式为准双向⼝。while(1)使程序处于流⽔灯循环不停⽌。
/*主函数*/
void main()
{
P0M0=0;    //定义I/O⼝⼯作模式
P0M1=0;
P1M0=0;
P1M1=0;
P2M0=0;
P2M1=0;
P3M0=0;
P3M1=0;
P4M0=0;
P4M1=0;
while(1)
{
LED();
}
}
⾄此,本实验讲解完毕,实验很简单,笔者也是刚⼊门,写的东西对于单⽚机有所经验的⼈来说有所赘余,但对刚接触单⽚机的同学肯定有所帮助!⼀次肝完的,有些地⽅也未深⼊讲解,不懂的同学可以留⾔。希望⼤家能点个赞!
下次⽂章为按键如何⽤中断实现,祝⼤家⼀切顺利!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。