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

embedded/2024/11/29 4:13:02/

上一节博客给大家基本介绍了单片机>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端口,实现各种复杂的功能。


http://www.ppmy.cn/embedded/141352.html

相关文章

TCP/IP网络编程-C++(上)

TCP/IP网络编程-C &#xff08;上&#xff09; 一、基于TCP的服务端/客户端1、server端代码2、client端代码3、socket() 函数3.1、函数原型3.2、参数解析3.2.1、协议族&#xff08;domain参数&#xff09;3.2.2、套接字类型&#xff08;type参数&#xff09;3.2.3、最终使用的协…

【C++】string类练习

test1:反转字母 给你一个字符串 s &#xff0c;根据下述规则反转字符串&#xff1a; 所有非英文字母保留在原有位置。所有英文字母&#xff08;小写或大写&#xff09;位置反转。 返回反转后的 s 。 示例 1&#xff1a; 输入&#xff1a;s "ab-cd" 输出&#xff1a;…

微知-lspci访问到指定的PCIe设备的几种方式?(lspci -s bus;lspci -d devices)

通过bdf号查看 -s &#xff08;bus&#xff09; lspci -s 03:00.0通过vendor id或者device id等设备查看 -d &#xff08;device&#xff09; lspci -d 15b3: #这里是vendor号&#xff0c;所以在前面 lspci -d :1021 #这里是设备号&#xff0c;所以要:在前vendorid和deviceid…

Postman定义公共函数

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Postman定义公共函数 在postman中&#xff0c;如下面的代码&#xff1a; 1、返回元素是否与预期值一致 var assertEqual(name,actual,expected)>{tests[…

视频 wmv 转MP4

ffmpeg -i input.wmv -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 192k output.mp4命令说明 -i input.wmv&#xff1a; 指定输入文件 input.wmv。 -c:v libx264&#xff1a; 使用 H.264 视频编码&#xff0c;适用于 MP4 格式。 -crf 23&#xff1a; 设置视频质量&#…

uniapp生命周期:应用生命周期和页面生命周期

文章目录 1.应用的生命周期2.页面的生命周期 1.应用的生命周期 生命周期的概念&#xff1a;一个对象从创建、运行、销毁的整个过程被称为生命周期 生命周期函数&#xff1a;在生命周期中每个阶段会伴随着每一个函数的出发&#xff0c;这些函数被称为生命周期函数 所有页面都…

微积分复习笔记 Calculus Volume 1 - 6.8 Exponential Growth and Decay

6.8 Exponential Growth and Decay - Calculus Volume 1 | OpenStax

栈和队列——考研笔记

文章目录 一.栈&#xff08;Stack&#xff09;基本概念1.栈的基本操作2.栈的常考题型 二.顺序栈的实现1.顺序栈的定义2.增&#xff08;进栈操作&#xff09;3.删&#xff08;出栈操作&#xff09;4.共享栈&#xff08;两个栈共享同一片空间&#xff09; 三.链栈的实现1.头插法建…