51单片机从入门到精通:理论与实践指南入门篇(三)

上一节博客给大家基本介绍了51单片机

51单片机从入门到精通:理论与实践指南入门篇(二)

https://blog.csdn.net/speaking_me/article/details/144068159?spm=1001.2014.3001.5501

那么这节课就来介绍------花样流水灯的实现

花样流水灯电路设计

1. 所需材料

  • 51系列单片机(如AT89S51)
  • LED灯若干(根据需要的数量选择)
  • 限流电阻若干(每个LED灯都需要一个)
  • 开关电源或电池
  • 连接线
  • 实验板或PCB板

2. 电路连接

  • 将每个LED灯的一端通过一个限流电阻连接到51单片机的一个I/O口(例如P1.0到P1.7),另一端连接到地(GND)。这样,当对应的I/O口输出高电平时,LED灯就会亮起;当输出低电平时,LED灯熄灭。
  • 确保电源电压适合51单片机的工作电压(通常是5V)。

C51语言知识精讲

C51语言是专门为51系列单片机设计的一种C语言变种,它在标准C语言的基础上增加了一些特定于51单片机的特性和关键字,以便更好地适应嵌入式系统的开发需求。以下是C51语言的一些关键特性和概念,这些特性使得C51语言成为51单片机编程的理想选择。

C51语言的关键特性

1. 特殊功能寄存器(SFR)和位操作
  • sfr :用于定义特殊功能寄存器(Special Function Register)。这些寄存器用于控制单片机的各种功能,如I/O端口、定时器、中断等。

    复制代码
    sfr P1 = 0x90;  // 定义P1端口寄存器,地址为0x90
  • sfr16 :用于定义16位的特殊功能寄存器。

    复制代码
    sfr16 DPTR = 0x82;  // 定义数据指针寄存器,地址为0x82
  • sbit :用于定义特殊功能寄存器中的某一位。

    复制代码
    sbit LED = P1^0;  // 定义P1端口的第0位为LED
2. 存储器类型

C51语言支持多种存储器类型,这些类型决定了变量或函数在单片机内存中的存储位置。

  • code :程序存储器,用于存放常量和函数。

    复制代码
    const char str[] code = "Hello, World!";  // 存储在程序存储器中的字符串
  • data :内部RAM的直接寻址区域,用于存放小型变量。

    复制代码
    unsigned char var1 data;  // 存储在内部RAM中的变量
  • xdata :外部RAM,用于存放大型变量。

    复制代码
    unsigned int var2 xdata;  // 存储在外部RAM中的变量
  • idata :内部RAM的间接寻址区域。

    复制代码
    unsigned char var3 idata;  // 存储在内部RAM间接寻址区域的变量
  • pdata :外部RAM的256字节区域,使用间接寻址。

    复制代码
    unsigned char var4 pdata;  // 存储在外部RAM间接寻址区域的变量
  • bdata :内部RAM的位寻址区域。

    复制代码
    unsigned char var5 bdata;  // 存储在内部RAM位寻址区域的变量
3. 位变量和位操作
  • bit :用于定义位变量,值只能是0或1。

    复制代码
    bit flag;  // 定义一个位变量
    flag = 1;  // 设置位变量为1
  • 位操作符 :C51支持位操作符,如&(按位与)、|(按位或)、^(按位异或)、~(按位取反)等。

    复制代码
    unsigned char a = 0x0F;
    unsigned char b = 0xF0;
    unsigned char c = a | b;  // c = 0xFF
4. 中断函数

C51语言支持中断函数的定义,这些函数用于处理单片机的中断事件。

  • interrupt :用于定义中断函数。
    复制代码
    void Timer0_ISR() interrupt 1 {
        // 中断服务例程
    }
5. 数据类型

C51语言支持多种数据类型,包括标准C语言中的数据类型以及一些扩展的数据类型。

  • 基本数据类型charintlongfloat等。
  • 扩展数据类型bitsfrsfr16sbit等。

与C语言相比

C51语言在很多方面与标准C语言是非常相似的。然而,也有一些细微的差别和额外的功能,这些是为了更好地适应嵌入式系统开发的需求。以下是一些主要的相似之处和差异:

相似之处
  1. 基本语法

    • 变量声明 :变量的声明和初始化方式与标准C语言相同。

      复制代码
      int a = 10;
      char b = 'A';
      float c = 3.14;
    • 控制结构ifelseforwhiledo-while等控制结构的使用方式与标准C语言相同。

      复制代码
      if (a > 0) {
          // 执行某些操作
      } else {
          // 执行其他操作
      }
      
      for (int i = 0; i < 10; i++) {
          // 循环体
      }
      
      while (condition) {
          // 循环体
      }
  2. 函数定义

    • 函数的定义和调用方式与标准C语言相同。
      复制代码
      void myFunction(int param) {
          // 函数体
      }
      
      int main() {
          myFunction(5);
          return 0;
      }
  3. 运算符

    • 基本的算术运算符、关系运算符、逻辑运算符等与标准C语言相同。
      复制代码
      int sum = a + b;
      int product = a * b;
      int result = (a > b) ? a : b;
  4. 数组和指针

    • 数组和指针的使用方式与标准C语言相同。
      复制代码
      int array[5] = {1, 2, 3, 4, 5};
      int *ptr = array;
      int value = *ptr;
差异之处
  1. 存储器类型

    • C51语言引入了特定的存储器类型关键字,如dataxdataidatapdatabdatacode等,这些关键字用于指定变量或函数在单片机内存中的存储位置。
      复制代码
      unsigned char data var1;  // 存储在内部RAM中的变量
      unsigned int xdata var2;  // 存储在外部RAM中的变量
      const char str[] code = "Hello, World!";  // 存储在程序存储器中的字符串
  2. 特殊功能寄存器(SFR)

    • C51语言提供了sfrsfr16关键字,用于定义特殊功能寄存器。
      复制代码
      sfr P1 = 0x90;  // 定义P1端口寄存器,地址为0x90
      sfr16 DPTR = 0x82;  // 定义数据指针寄存器,地址为0x82
  3. 位操作

    • C51语言提供了bitsbit关键字,用于定义位变量和特殊功能寄存器中的位。
      复制代码
      bit flag;  // 定义一个位变量
      sbit LED = P1^0;  // 定义P1端口的第0位为LED
  4. 中断函数

    • C51语言支持中断函数的定义,这些函数用于处理单片机的中断事件。
      复制代码
      void Timer0_ISR() interrupt 1 {
          // 中断服务例程
      }
  5. 库函数

    • C51语言的库函数与标准C语言有所不同,许多标准C库函数可能不适用于嵌入式系统,而C51库函数则专门针对51单片机进行了优化。
      复制代码
      #include <intrins.h>  // 包含内建函数头文件
      _nop_();  // 插入一个空操作指令
  6. 存储模式

    • C51语言支持不同的存储模式,如SMALLCOMPACTLARGE,这些模式影响变量和指针的默认存储位置。
      复制代码
      #pragma small  // 设置存储模式为SMALL

示例程序:51单片机控制LED流水灯

以下是一个使用C51语言编写的示例程序,该程序控制51单片机的P1端口上的8个LED灯以流水灯的形式依次点亮。

复制代码
#include <reg51.h>

// 定义延时函数
void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    // 设置P1口为输出模式
    P1 = 0xFF;   // 初始状态下所有LED灯都关闭

    while(1) {   // 无限循环
        P1 = 0xFE; // 第一个LED灯亮,其余熄灭
        delay(500);
        P1 = 0xFD; // 第二个LED灯亮,其余熄灭
        delay(500);
        P1 = 0xFB; // 第三个LED灯亮,其余熄灭
        delay(500);
        P1 = 0xF7; // 第四个LED灯亮,其余熄灭
        delay(500);
        P1 = 0xEF; // 第五个LED灯亮,其余熄灭
        delay(500);
        P1 = 0xDF; // 第六个LED灯亮,其余熄灭
        delay(500);
        P1 = 0xBF; // 第七个LED灯亮,其余熄灭
        delay(500);
        P1 = 0x7F; // 第八个LED灯亮,其余熄灭
        delay(500);
        P1 = 0xFF; // 所有LED灯熄灭
        delay(500);
    }
}

学习其他方法控制流水灯

1. 位操作控制流水灯

思路

通过直接操作寄存器的某一位来控制LED灯的亮灭。使用sbit关键字定义特定的位。

代码
复制代码
#include <reg51.h>

sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
sbit LED5 = P1^4;
sbit LED6 = P1^5;
sbit LED7 = P1^6;
sbit LED8 = P1^7;

void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    while(1) {
        LED1 = 0; delay(500); LED1 = 1;
        LED2 = 0; delay(500); LED2 = 1;
        LED3 = 0; delay(500); LED3 = 1;
        LED4 = 0; delay(500); LED4 = 1;
        LED5 = 0; delay(500); LED5 = 1;
        LED6 = 0; delay(500); LED6 = 1;
        LED7 = 0; delay(500); LED7 = 1;
        LED8 = 0; delay(500); LED8 = 1;
    }
}

2. 字节操作控制流水灯

思路

通过操作整个字节来控制一组LED灯。使用字节操作符来改变P1端口的值。

代码
复制代码
#include <reg51.h>

void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    while(1) {
        P1 = 0xFE; delay(500);  // 第一个LED灯亮
        P1 = 0xFD; delay(500);  // 第二个LED灯亮
        P1 = 0xFB; delay(500);  // 第三个LED灯亮
        P1 = 0xF7; delay(500);  // 第四个LED灯亮
        P1 = 0xEF; delay(500);  // 第五个LED灯亮
        P1 = 0xDF; delay(500);  // 第六个LED灯亮
        P1 = 0xBF; delay(500);  // 第七个LED灯亮
        P1 = 0x7F; delay(500);  // 第八个LED灯亮
    }
}

3. 移位运算符控制流水灯

思路

通过移位运算符来改变字节的值,从而控制LED灯的亮灭。

代码
复制代码
#include <reg51.h>

void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    unsigned char mask = 0x01;
    while(1) {
        for(int i = 0; i < 8; i++) {
            P1 = ~mask;  // 取反,使LED灯亮
            delay(500);
            mask <<= 1;  // 左移一位
        }
        mask = 0x01;  // 重置mask
    }
}

4. 库函数控制流水灯

思路

使用51单片机的内置库函数来实现循环移位,简化代码。

代码
复制代码
#include <reg51.h>
#include <intrins.h>

void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    unsigned char mask = 0x01;
    while(1) {
        for(int i = 0; i < 8; i++) {
            P1 = ~mask;  // 取反,使LED灯亮
            delay(500);
            mask = _crol_(mask, 1);  // 循环左移一位
        }
        mask = 0x01;  // 重置mask
    }
}

5. 条件控制语句控制流水灯

思路

使用if语句来控制LED灯的亮灭。

代码
复制代码
#include <reg51.h>

void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    unsigned char state = 0x01;
    while(1) {
        if (state == 0x01) {
            P1 = 0xFE; delay(500);
            state = 0x02;
        } else if (state == 0x02) {
            P1 = 0xFD; delay(500);
            state = 0x04;
        } else if (state == 0x04) {
            P1 = 0xFB; delay(500);
            state = 0x08;
        } else if (state == 0x08) {
            P1 = 0xF7; delay(500);
            state = 0x10;
        } else if (state == 0x10) {
            P1 = 0xEF; delay(500);
            state = 0x20;
        } else if (state == 0x20) {
            P1 = 0xDF; delay(500);
            state = 0x40;
        } else if (state == 0x40) {
            P1 = 0xBF; delay(500);
            state = 0x80;
        } else if (state == 0x80) {
            P1 = 0x7F; delay(500);
            state = 0x01;
        }
    }
}

6. switch语句控制流水灯

思路

使用switch语句来控制LED灯的亮灭。

代码
复制代码
#include <reg51.h>

void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    unsigned char state = 0x01;
    while(1) {
        switch(state) {
            case 0x01:
                P1 = 0xFE; delay(500); state = 0x02; break;
            case 0x02:
                P1 = 0xFD; delay(500); state = 0x04; break;
            case 0x04:
                P1 = 0xFB; delay(500); state = 0x08; break;
            case 0x08:
                P1 = 0xF7; delay(500); state = 0x10; break;
            case 0x10:
                P1 = 0xEF; delay(500); state = 0x20; break;
            case 0x20:
                P1 = 0xDF; delay(500); state = 0x40; break;
            case 0x40:
                P1 = 0xBF; delay(500); state = 0x80; break;
            case 0x80:
                P1 = 0x7F; delay(500); state = 0x01; break;
        }
    }
}

7. 数组控制流水灯

思路

使用数组来存储每个LED灯的状态,通过索引来控制LED灯的亮灭。

代码
复制代码
#include <reg51.h>

void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    unsigned char led_states[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
    while(1) {
        for(int i = 0; i < 8; i++) {
            P1 = led_states[i];
            delay(500);
        }
    }
}

8. 指针控制流水灯

思路

使用指针来遍历数组,通过指针来控制LED灯的亮灭。

代码
复制代码
#include <reg51.h>

void delay(unsigned int time) {
    unsigned int i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 1275; j++);
}

void main() {
    unsigned char led_states[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
    unsigned char *ptr = led_states;
    while(1) {
        for(int i = 0; i < 8; i++) {
            P1 = *ptr;
            delay(500);
            ptr++;
        }
        ptr = led_states;  // 重置指针
    }
}

总结

以上是使用位操作、字节操作、移位运算符、库函数、条件控制语句、switch语句、数组和指针这8种方法来控制51单片机上的流水灯的详细讲解和代码示例。每种方法都有其独特的优点和适用场景,通过学习这些方法,你可以更灵活地控制51单片机的I/O端口,实现各种复杂的功能。

相关推荐
森利威尔电子-1 小时前
森利威尔SL3180 替换LTC3639 150V降压恒压芯片 3A峰值电流能力转换效率高 静态电流低
单片机·嵌入式硬件·集成电路·芯片·电源芯片
qq_401700411 小时前
合宙4G模块Air724UG
嵌入式硬件
yugi9878382 小时前
基于51单片机的篮球计分器设计
单片机·嵌入式硬件·51单片机
编程之升级打怪2 小时前
什么是PWM
嵌入式硬件
zmj3203243 小时前
单片机内存在C 语言编译后的 “逻辑分区”
c语言·单片机·内存分区
小柯博客4 小时前
STM32MP2 Secure Boot实战
stm32·单片机·嵌入式硬件
Ww.xh4 小时前
STM32调用AI接口完整教程
stm32·单片机·嵌入式硬件
ZYNQRFSOC4 小时前
基于安路PH2A系列FPGA的JESD204B接口测试
嵌入式硬件·fpga开发
LCG元5 小时前
STM32实战:基于STM32F407的LWIP以太网通信(TCP Server)
stm32·嵌入式硬件·tcp/ip
项目題供诗6 小时前
STM32-按键控制LED&光敏传感器控制蜂鸣器(五)
stm32·单片机·嵌入式硬件