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

news/2024/12/4 15:30:32/

上一节博客给大家基本介绍了单片机>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/news/1552312.html

相关文章

网络安全系列 之 SQL注入学习总结

目录 1. sql注入概述2. sql注入测试工具3. sql注入防御方法 3.1 问题来源3.2 防御方法4. SQL注入防御举例 4.1 使用JDBC时&#xff0c;SQL语句进行了拼接 1. 使用statement的executeQuery、execute、executeUpdate等函数时&#xff0c;传入的SQL语句拼接了来自外部的不可信参数…

联想YOGA Pro 14s至尊版电脑找不到独立显卡(N卡)问题,也无法安装驱动的问题

问题描述 电脑是联想YOGA Pro 14s至尊版&#xff0c;电脑上装的独立显卡是4060&#xff0c;一直是能够使用独立显卡的。然而有两次突然就找不到显卡了&#xff0c;NVIDIA CONTROL PANEL也消失了&#xff0c;而且也无法安装驱动。具体表现如下&#xff1a; 无法连接外接显示器…

【音视频】HLS和DASH 流媒体协议的详细介绍和实现方式

深入探讨 HLS 和 DASH 流媒体协议 1. HLS&#xff08;HTTP Live Streaming&#xff09; 核心技术细节 HLS&#xff08;HTTP Live Streaming&#xff09;是由苹果公司提出的一种基于 HTTP 协议的流媒体协议。它将视频分割成多个小片段&#xff0c;通过 .m3u8 文件作为索引进行…

解决 el-input 红色波浪线问题

解决 el-input 红色波浪线问题 添加 spellcheck"false" <el-input class"inputStyle" v-model"codeNum" spellcheck"false" change"orderFn" ref"inputSelectBound" label""></el-input>…

代码随想录-算法训练营day29(回溯算法05:非递减子序列,全排列,全排列2)

第七章 回溯算法part05* 491.递增子序列 * 46.全排列 * 47.全排列 II详细布置 491.递增子序列 本题和大家刚做过的 90.子集II 非常像&#xff0c;但又很不一样&#xff0c;很容易掉坑里。 https://programmercarl.com/0491.%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97.htm…

Python 入门教程(2)搭建环境 | 2.4、VSCode配置Node.js运行环境

文章目录 一、VSCode配置Node.js运行环境1、软件安装2、安装Node.js插件3、配置VSCode4、创建并运行Node.js文件5、调试Node.js代码 一、VSCode配置Node.js运行环境 1、软件安装 安装下面的软件&#xff1a; 安装Node.js&#xff1a;Node.js官网 下载Node.js安装包。建议选择L…

【Go底层】select原理

目录 1、背景2、go版本3、 selectgo函数解释【1】函数参数解释【2】函数具体解释第一步&#xff1a;遍历pollorder&#xff0c;选出准备好的case第二步&#xff1a;将当前goroutine放到所有case通道中对应的收发队列上第三步&#xff1a;唤醒groutine 4、总结 1、背景 select多…

SpringBoot 框架下基于 MVC 的高校办公室行政事务管理系统:设计开发全解析

2系统开发环境 2.1vue技术 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。 [5] 与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第…