【小白51单片机专用教程】protues仿真流水灯

课程特点

  • 无需开发板
  • 0基础教学
  • 软件硬件双修
  • 辅助入门

本课程面对纯小白,因此会对各个新出现的知识点在实例基础上进行详细讲解,有相关知识的可以直接跳过。课程涉及protues基本操作、原理图设计、数电模电、kell使用、C语言基本内容,所有涉及知识都将建立在实例的基础上放心食用。

食用教程

  • 详细目录,随时跳过已知部分;
  • 全小白按步骤全程跟学;
  • 有开发板的交叉理解开发板的原理图与我们设计的原理图

本次实验内容

设计4个LED等,通过编程控制实现流水灯,流水灯间隔时间为500ms;进一步熟悉protues和keil软件,初步了解单片机的机械周期,理解自定义定时函数的设计思路。

前言

该篇内容在硬件设计上没有太多特别,具体设计思路在protues仿真C51入门教程,本篇文章主要内容在其C语言的设计上:自定义函数以及如何用函数粗略实现定时

流水灯是多个小灯泡依次点亮,视觉上像流水一样。

protues原理图设计

我们此次设计4个LED,调出3个LED,3个电阻设置电阻阻值为280,并按图连线

编程

51单片机的IO口默认是高电平,因此上电时LED均会亮,所以在程序的编写上,第一步是先将LED灯均熄灭。然后将D1~D4依次点亮,再全部熄灭,再依次点亮,如此反复。

C语言知识讲解
自定义函数

自定义函数顾名思义自己定义设计的函数,其形式为:

cs 复制代码
[储存类型符]  [返回值类型符]  函数名([形参说明表])
{
    函数语句体
}

储存类型符:一共有四种,一般情况下不写,这里不详细讲解

返回值类型符:值函数运行完需要返回的东西,例如我们主函数main的返回值为void,表示空,不返回任何东西

函数名:自定义函数名字,大致要求是由大小写字母或下划线组成,不能太长,第一个字符不能是数字,具体要求自行搜索。

形参说明表:一系列逗号分开的形参变量数据类型声明。如"int a,int b"表示有两个整数变量x,y,int表示整数。

for循环语句

for循环语句形式为:

cs 复制代码
for (初始化; 条件; 迭代) {
    // 循环体
}

例如:

cs 复制代码
for (i = 0; i < 5; i++) {

}

在这个例子中,for 循环从 i = 0 开始执行大括号中的内容(这里为空),每次执行完后迭代 i 增加 1,直到 i 不再小于5,循环结束。

延时函数设计

如果执行一条指令要1ms,那么我执行1000条指令就是1s。所以该函数设计的重点是执行一条指令的实际时间及其执行次数。

8051的机器周期

在C51单片机中,要实现1秒的延时,我们需要知道晶振频率和机器周期的关系。C51单片机的机器周期晶振频率的12分频(既除以12)。我们的晶振频率是11.0592MHz,那么机器周期大约为:

晶振频率代入计算得到:

现在我们知道每个机器周期大约是1.085微秒。为了实现1毫秒的延时,我们需要执行多少个机械周期

因此我们大致知道我们需要执行921个机械周期

那么怎么让程序执行921个机械周期呢?这就涉及到汇编语言了,C语言是高级语言,主要是便于我们编程者设计,难以直接判断其机械周期。实际上,C语言在编译后会转换为汇编语言,这个才是判断其机械周期的关键。

因此设计一个可以定时的函数需要了解其汇编语言,在这里我们不去深究与探讨,有兴趣的可以自性了解,或者私信留言。这里我们只是将这种思维转达给各位。

这里我们提供一个函数是:

cs 复制代码
void delay_ms(unsigned n)
{
    unsigned int i,j;
    for(i=n;i>0;i--)
        for(j=114;j>0;j--);
}

该函数经过严格验证,其运行时间在1ms左右。

该函数的汇编指令如下:

cs 复制代码
C:0x005D    7D72     MOV      R5,#0x72
C:0x005F    7C00     MOV      R4,#0x00
C:0x0061    ED       MOV      A,R5
C:0x0062    1D       DEC      R5
C:0x0063    7001     JNZ      C:0066
C:0x0065    1C       DEC      R4
C:0x0066    ED       MOV      A,R5
C:0x0067    4C       ORL      A,R4
C:0x0068    70F7     JNZ      C:0061
C:0x006A    EF       MOV      A,R7
C:0x006B    1F       DEC      R7
C:0x006C    70E6     JNZ      delay_ms(C:0054)

其主要循环部分大致8个机械周期,921/8约等于114,因此循环114次大致1ms

流水灯程序设计
cs 复制代码
#include "reg51.h"

sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P1^2;
sbit LED4=P1^3;

void delay_ms(unsigned n)
{
    unsigned int i,j;
    for(i=n;i>0;i--)
        for(j=114;j>0;j--);
}

void main(){
    LED1=0;
    LED2=0;
    LED3=0;
    LED4=0;
    
    while(1){
        LED1=1;
        LED2=0;
        LED3=0;
        LED4=0;
        delay_ms(500);
        
        LED1=0;
        LED2=1;
        LED3=0;
        LED4=0;
        delay_ms(500);
        
        LED1=0;
        LED2=0;
        LED3=1;
        LED4=0;
        delay_ms(500);
        
        LED1=0;
        LED2=0;
        LED3=0;
        LED4=1;
        delay_ms(500);
    }
    
}

分别定义原理图中D1~D4的控制引脚为LED1~LED4

cs 复制代码
sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P1^2;
sbit LED4=P1^3;

主函数结构

cs 复制代码
void main(){
    //初始化区
    while(1){
        //循环区
    }
}

初始化区一般进行一些变量的定义初始状态的设置 ,在这里我们初始化让D1~D4熄灭

cs 复制代码
    LED1=0;
    LED2=0;
    LED3=0;
    LED4=0;

循环区一般运行主要程序 ,单片机会不断重复执行里面内容。在这里我们依次点亮LED灯,点亮一个灯的同时关闭其它灯,经过500ms,再点亮下一个灯熄灭其它灯,如此反复。

cs 复制代码
        LED1=1;
        LED2=0;
        LED3=0;
        LED4=0;
        delay_ms(500);
        
        LED1=0;
        LED2=1;
        LED3=0;
        LED4=0;
        delay_ms(500);
        
        LED1=0;
        LED2=0;
        LED3=1;
        LED4=0;
        delay_ms(500);
        
        LED1=0;
        LED2=0;
        LED3=0;
        LED4=1;
        delay_ms(500);

点击编译

看到生成hex文件成功即可。

报0Error即可,但警告太多还是要看一下。

protues验证

打开protues点击开始仿真(没有加载hex文件的记得双击芯片加载hex文件)

现象:点击开始D1~D4不亮->D1亮,其它不亮->D2亮,其它不亮->D3亮,其它不亮->D4亮,其它不亮->D1亮,其它不亮->...如此循环

protues仿真流水灯(C51)

代码优化

我们可以看到,我们的代码有大量的重复的内容,对这一部分我们进行优化,对于重复内容我们可以设计一个函数去执行,但又不能破坏其功能。那么我们设计一个函数。可以同时控制4个灯的状态

cs 复制代码
void LEDdisplay(int L1,int L2,int L3,int L4){
    LED1=L1;
    LED2=L2;
    LED3=L3;
    LED4=L4;
}

如此我们的程序将变成:

cs 复制代码
#include "reg51.h"

sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P1^2;
sbit LED4=P1^3;

void delay_ms(unsigned n)
{
    unsigned int i,j;
    for(i=n;i>0;i--)
        for(j=273;j>0;j--);
}

void LEDdisplay(int L1,int L2,int L3,int L4){
    LED1=L1;
    LED2=L2;
    LED3=L3;
    LED4=L4;
}

void main(){
    LEDdisplay(0,0,0,0);
    
    while(1){
        LEDdisplay(1,0,0,0);
        delay_ms(500);
        
        LEDdisplay(0,1,0,0);
        delay_ms(500);
        
        LEDdisplay(0,0,1,0);
        delay_ms(500);
        
        LEDdisplay(0,0,0,1);
        delay_ms(500);
    }
    
}

在主函数这里是不是相对程序简单了很多呢?

总结

protuse仿真C51流水灯的硬件设计并没有特别需要讲解的,主要是需要设计一个可以粗略定时的函数,理解其设计思路,了解单片机的机械周期以及C语言函数的基本形式。

相关推荐
楼台的春风1 小时前
【STM32 基于PID的闭环电机控制系统】
c语言·stm32·单片机·嵌入式硬件·mcu·物联网·算法
stm32发烧友1 小时前
基于STM32的智能电力监测与需求响应系统
stm32·单片机·嵌入式硬件
Turnin111112 小时前
stm32四种方式精密控制步进电机
单片机·嵌入式硬件·电机控制
promising-w2 小时前
【蓝桥杯单片机】第十三届省赛第二场
单片机·蓝桥杯
SRA.3 小时前
STM32——HAL库开发笔记22(定时器3—呼吸灯实验)(参考来源:b站铁头山羊)
笔记·stm32·嵌入式硬件
SRA.3 小时前
STM32——HAL库开发笔记21(定时器2—输出比较)(参考来源:b站铁头山羊)
笔记·stm32·嵌入式硬件
日记成书6 小时前
详细介绍嵌入式硬件设计
嵌入式硬件·深度学习·学习
wenchm6 小时前
细说STM32F407单片机1个ADC使用DMA同时采集3个输入通道的方法
stm32·单片机·嵌入式硬件
SRA.6 小时前
STM32——HAL库开发笔记23(定时器4—输入捕获)(参考来源:b站铁头山羊)
笔记·stm32·嵌入式硬件
打酱油的工程师7 小时前
w803|联盛德|WM IoT SDK2.X测试|window11|TOML 文件|外设|TFT_LCD|测试任务|(5):TFT_LCD_LVGL示例
单片机·物联网·lcd·tft·w80x