51单片机教程(六)- LED流水灯

news2024/12/28 15:31:27

1 项目分析

  • 基于点亮LED灯、LED灯闪烁,扩展到构成最简单、花样流水灯。

2 技术准备

1 流水灯硬件及原理图

  • 流水灯是由多个LED灯组成的

    在这里插入图片描述
    在这里插入图片描述

2 C语言知识点

  • 数组
    • 数组声明:长度不可变

      • 数据类型 数组名称[长度n] // 整数型默认为0,小数型默认为0.0,字符默认为 ‘\0’,字符串默认为:NULL

    • 声明数组并初始化

      • 数据类型 数组名称[长度n] = {元素1,元素2…元素n};
      • 数据类型 数组名称[] = {元素1,元素2…元素n};

    • 访问:索引值从0开始

      • 数组名称[索引];

    • 数组长度

      • sizeof(数组名称) / sizeof(数组名称[0])

    • 修改数组中对应索引值位置的数据

      • 数组名称[0] = 元素1;
      • 数组名称[1] = 元素2;
      • 数组名称[n-1] = 元素n;

    • 遍历数组中的每个数据

      for (int i = 0; i <sizeof(array) / sizeof(arr[0]); i++)
      {
      		arrray[i]   // 相关操作
      }
      
      // 数组的基本使用
      
      #include <stdio.h>
      
      int main()
      {
      	// 数组的定义
      	int score[5];
      
      	// 数组的初始化(重点)
      	int scores[5] = {34, 55, 67, 88, 19};
      	int score1[] = {34, 55, 67, 88, 19};
      	
      	// 数组的索引:从0开始(重点)
      	printf("%d ", scores[3]);
      	
      	// 数组的索引赋值
      	scores[4] = 99;
      	printf("%d ", scores[4]);
      	
      	// 数组的长度
      	printf("\n长度:%d", sizeof(scores));
      	printf("\n长度:%d", sizeof(scores) / sizeof(scores[0]));
      	
      	// 数组的遍历(重点)
      	int x = 0;
      	for(; x < 5; x++)
      	{
      		printf(" %d ", scores[x]);
      	}
      	 
      	return 0;
      } 
      

3 延时

  • 介绍

    • 每条指令都占一定的时间(或者机器周期)的,如果让机器什么都不做,即空指令的话,机器就会延时,然后在计算好每次延时到底有多长,外面套一个循环(或者多重循环),根据想要的延时时间即可计算出来循环的次数,延时函数基本上都是这种原理,它的参数就是用来控制循环次数的。

    • 实现延时通常有两种方法:

      1. 硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;
      2. 软件延时,这种方法主要采用循环体进行。
  • 分类

    • 1)硬件延时: 使用定时器/计数器实现精确延时
    • 2)软件延时: 软件延时与时间计算
      • 在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。
  • 方法

    • 短暂延时 nop (intrins.h头文件)
      • 在C51中嵌套汇编程序段实现延时
    • 使用示波器确定延时时间
      • 使用反汇编工具计算延时时间

3 项目实现

方式1:常规方法

  • 实验

    • 结合多个LED灯实现流水灯效果,每个灯亮灭间隔大约2s
  • 代码

      /*
      	代码实现思路:
      		0 搭建代码框架
      		1 定义8个LED灯的端口
      		2 在while循环中,控制每个LED灯亮灭
      		3 需要设置每个LED灯亮灭的间隔(延迟函数)
      */
      
      #include <reg52.h>
      
      // 宏定义
      #define uint unsigned int
      
      // 1 定义8个LED灯的端口
      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(uint s);
      
      void main()
      {
      	while(1)
      	{
      		// 2 在while循环中,控制每个LED灯亮灭
      		led1 = 0;  // led1 亮
      		delay(2);
      		led1 = 1;
      		led2 = 0;
      		delay(2);
      		led2 = 1;
      		led3 = 0;
      		delay(2);
      		led3 = 1;
      		led4 = 0;
      		delay(2);
      		led4 = 1;
      		led5 = 0;
      		delay(2);
      		led5 = 1;
      		led6 = 0;
      		delay(2);
      		led6 = 1;
      		led7 = 0;
      		delay(2);
      		led7 = 1;
      		led8 = 0;
      		delay(2);
      		led8 = 1;
      	}	
      }
      
      void delay(uint s)
      {
        uint i,j,z;
      	for(z=0;z<s;z++)
      	{
      		for(i=0; i<183; i++)
      		{
      			for(j=0; j<1000; j++);
      		}
      	}    
      }
    

方式2:P1口赋予十六进制

  • 实验

    • 结合多个LED灯实现流水灯效果,每个灯亮灭间隔大约2s
  • 分析
    在这里插入图片描述

  • 代码

    /*
    	代码实现思路:
    		0 搭建代码框架
    		1 定义P1的端口
    		2 在while循环中,控制P1的取值
    		3 需要设置P1端口取值后间隔(延迟函数)
    */
    
    #include <reg52.h>
    
    // 宏定义
    #define uint unsigned int
    
    // 1 定义P1的端口
    #define led P1
    
    // 函数声明
    void delays(uint s);
    
    void main2()
    {
    	while(1)
    	{
    		// 2 在while循环中,控制P1的取值,集合延迟函数
    		led = 0xfe;  // led1 亮
    		delays(1);
    		led = 0xfd;  // led2 亮
    		delays(1);
    		led = 0xfb;  // led3 亮
    		delays(1);
    		led = 0xf7;  // led4 亮
    		delays(1);
    		led = 0xef;  // led5 亮
    		delays(2);
    		led = 0xdf;  // led6 亮
    		delays(2);
    		led = 0xbf;  // led7 亮
    		delays(2);
    		led = 0x7f;  // led8 亮
    		delays(2);
    	}	
    }
    
    void delays(uint s)
    {
      uint i,j,z;
    	for(z=0;z<s;z++)
    	{
    		for(i=0; i<183; i++)
    		{
    			for(j=0; j<1000; j++);
    		}
    	}    
    }
    

方式3:数组存储P1电平值

  • 实验
    • 结合多个LED灯实现流水灯效果,每个灯亮灭间隔大约2s
  • 代码
    /*
    	代码实现思路:
    		0 搭建代码框架
    		1 定义P1的端口
    		2 定义数组,存储8个P1的值
    		3 在while循环中,再循环获取数组中的值,赋值给P1
    		4 需要设置P1端口取值后间隔(延迟函数)
    */
    
    #include <reg52.h>
    
    // 宏定义
    #define uint unsigned int
    
    // 1 定义P1的端口
    #define led P1
    
    // 2 定义数组,存储8个P1的值
    uint led_value[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
    
    // 3.1 定义变量,用来表示索引值
    uint idx;
    
    // 函数声明
    void delay(uint s);
    
    void main()
    {
    	while(1)
    	{
    		// 3 在while循环中,再循环获取数组中的值,赋值给P1,配合延迟函数
    		for(idx=0; idx < 8; idx++)
    		{	
    			led = led_value[idx];  // ledx 亮
    			delay(1);
    		}
    	}	
    }
    
    void delay(uint s)
    {
      uint i,j,z;
    	for(z=0;z<s;z++)
    	{
    		for(i=0; i<183; i++)
    		{
    			for(j=0; j<1000; j++);
    		}
    	}    
    }
    

方式4: 按位左移 + 取反

  • 实验

    • 结合多个LED灯实现流水灯效果,每个灯亮灭间隔大约2s
  • 分析
    在这里插入图片描述

  • 代码

    /*
    	代码实现思路:
    		0 搭建代码框架
    		1 定义P1的端口
    		2 在while循环中,赋值给P1: ~(0x01 < n)
    		3 需要设置P1端口取值后间隔(延迟函数)
    */
    
    #include <reg52.h>
    
    // 宏定义
    #define uint unsigned int
    
    // 1 定义P1的端口
    #define led P1
    
    // 2.1 定义变量,用来表示左移的位数
    uint n;
    
    // 函数声明
    void delay(uint s);
    
    void main()
    {
    	while(1)
    	{
    		// 2 在while循环中,赋值给P1: ~(0x01 < n),配合延迟函数
    		for(n=0; n < 8; n++)
    		{	
    			led = ~(0x01 << n);  // ledx 亮
    			delay(2);
    		}
    	}	
    }
    
    void delay(uint s)
    {
      uint i,j,z;
    	for(z=0;z<s;z++)
    	{
    		for(i=0; i<183; i++)
    		{
    			for(j=0; j<1000; j++);
    		}
    	}    
    }
    

4 拓展:花样流水灯

花样灯1

  • 实验

    • 流水灯:全部亮 + 奇数灯亮 + 偶数灯亮
  • 代码

    /*
    	LED定义
    		单个灯:控制1~3个LED   sbit ledx = P1^x;
    		多个灯:控制8个LED     #define LED P1
    		
        全亮:P1.7 ~ P1.0 对应的端口都为低电平(0),将值写成16进制:0x00 --> 0
    		奇数灯亮(LED1 3 5 7-->P1.0 2 4 6)设置为低电平,写成16进制:0xaa
    		偶数灯亮(LED2 4 6 8-->P1.1 3 5 7)设置为低电平,写成16进制:0x55
    		
    代码的实现流程
    	1、定义代码的基本结构
    	2、定义P1端口,数组存储P1的值
    	3、在while循环中,遍历数组,并将值赋值给P1,同时设置对应延时
    */
    
    #include <reg52.h>
    #include <delay.h>
    
    #define uint unsigned int
    
    // 定义P1端口
    #define LED P1
    
    // 定义数组存储P1的值
    uint values[3] = {0x00, 0xaa, 0x55};
    
    void main1()
    {
    	uint idx;
    	while(1)
    	{
    		for(idx=0; idx<sizeof(values)/sizeof(values[0]); idx++)
    		{
    			LED = values[idx];
    			delay(1);
    		}
    	}
    }
    
    
    // file: delay.c
       /*
    	延迟函数:
    	功能:传入指定的值,延迟指定的秒数
    	参数:s 表示当前延迟的秒数
    	返回值:无
    */
    void delay(unsigned int s)
    {
    	unsigned int x, i, j;
    	for(x=0; x<s; x++)
    	{
    		for(i=0; i<183; i++)
    		{
    			for(j=0; j<1000; j++);
    		}
    	}
    }
    
    // file: delay.h
    #ifndef __DELAY_H  // if not define 如果没有定义
    #define __DELAY_H  // 定义对应头文件
    
    // 函数的声明
    void delay(unsigned int s);
    
    #endif      // 结束判断
    
     #include<reg52.h>
     
     unsigned char code table[] = {0x7f, 0xbf, 0xdf, 0xef,
                                   0xf7, 0xfb, 0xfd, 0xfe,
                                   0xff, 0xff, 0x00, 0x00,
                                   0x55, 0x55, 0xaa, 0xaa};
     
     void Delay(unsigned int t); //函数声明
     
     /*------------------------------------------------
                         主函数
     ------------------------------------------------*/
     void main()
     {
         unsigned char i;  //定义一个无符号字符型局部变量 i 取值范围 0~255
     
         while (1) {       //主循环
             for (i = 0; i < 16; i++) { //程序循环执行16次,表明表格中有16个元素
                 P1 = table[i];
                 Delay(10000);
             }
         }
     }
     
     /*------------------------------------------------
      延时函数,含有输入参数 unsigned int t,无返回值
      unsigned int 是定义无符号整形变量,其值的范围是 0~65535
     ------------------------------------------------*/
     void Delay(unsigned int t)
     {
         while (--t);
     }
    
    /*
    	定时器:T1 工作在模式1:65.536ms
    	 1s: 50ms * 20    次数 * 机器周期 = 0.05s  次数:50000
    		初值:65536 - 50000
    		
    代码的实现流程
    	1、定义代码的基本结构
    	2、定义P1端口、记录定时器次数、数组存储P1的值
    	3、在main函数中,定义定时器
    		(1) 设置定时器T1的工作模式1
    			TMOD = 0x10;
    		(2) 设置T1的TH1 TL1的值
    			TH1 = (65536 - 50000) / 256;
    			TL1 = (65536 - 50000) % 256;
    		(3) 打开“开关”
    			EA = 1;  // 打开总开关
    			TR1 = 1;   // 开启定时器T1
    			ET1 = 1;   // 开启定时器T1的外部中断
    	4、定义中断函数
    	  void 中断函数名()  interrupt 3
    		{
    			// 4.1 重置TH1 TL1
    			TH1 = (65536 - 50000) / 256;
    			TL1 = (65536 - 50000) % 256;
    			
    			// 4.2 定义变量,记录次数
    			变量++;
    			
    			// 4.3 判断变量是否等于20
    			if(变量==20)
    			{
    				// 流水灯逻辑
    			}
    		}
    	
    */
    
    #include <reg52.h>
    
    #define uint unsigned int
    
    // 定义P1端口
    #define LED P1
    
    // 定义记录中断函数执行次数
    uint times = 0;
    
    // 定义数组存储P1的值
    uint p1_value[3] = {0x00, 0xaa, 0x55};
    
    // 定义数组的索引
    uint index = 0;
    
    void main2()
    {
    	// (1) 设置定时器T1的工作模式1
    	TMOD = 0x10;
    	
    	// (2) 设置T1的TH1 TL1的值
    	TH1 = (65536 - 50000) / 256;
    	TL1 = (65536 - 50000) % 256;
    	
    	//	(3) 打开“开关”
    	EA = 1;
    	TR1 = 1;
    	ET1 = 1;
    		
    	while(1)
    	{
    	}
    }
    
    // 定时器T1的中断函数
    void timer1() interrupt 3
    {
    	// 4.1 重置TH1 TL1
    	TH1 = (65536 - 50000) / 256;
    	TL1 = (65536 - 50000) % 256;
    	
    	// 4.2 定义变量,记录次数
    	times++;
    	
    	// 4.3 判断变量是否等于20
    	if(times==20)    // 1s
    	{
    		// 判断index是否越界
    		if(index > 2)
    		{
    			index = 0;
    		}
    		
    		// 流水灯逻辑
    		LED = p1_value[index];
    		
    		// times重置
    		times = 0;
    		
    		// 改变index
    		index++;
    	}
    }
    

花样灯2

  • 实验

    • 每次2个灯左移 + 每次2个灯右移 + 全灭 + 全亮
  • 分析
    在这里插入图片描述

  • 代码

    #include <reg52.h>
    #include <delay.h>
    
    #define uint unsigned int
    	
    // 定义P1端口
    #define Led P1
    
    // 定义存储P1端口值的中间值的变量
    uint temp;
    
    void main3()
    {
    	uint x;
    	while(1)
    	{
    		// 左移:
    		Led = 0xfc;
    		temp = 0xfc;
    		
    		for(x=0; x<6; x++)
    		{
    			delay(1);
    			temp = temp << 1 | 0x01;
    			Led = temp;
    		}
    		
    		// 右移:
    		Led = temp;
    		
    		for(x=0; x<6; x++)
    		{
    			delay(1);
    			temp = temp >> 1 | 0x80;
    			Led = temp;
    		}
    		
    		// 全灭
    		delay(1);
    		Led = 0xff;
    		delay(1);
    		
    		// 全亮
    		Led = 0;
    		delay(1);
    	}
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2235158.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

供热的一些基础技术数据

1、应该了解的几个实用数据:(1)室内采暖达标温度182℃(2)建筑面积采暖热负荷 4060kcal/h㎡(4570W/㎡)(3)建筑面积采暖所需合理流量 2.53.5kg/h㎡(节能建筑12 kg/h㎡)(4)一次网严寒期外网总供、回水温度5570℃(5)热网的补水量应小于热网循环量的1%(6)1蒸吨的热量可供11.5 万平方…

【1个月速成Java】基于Android平台开发个人记账app学习日记——第7天,申请阿里云SMS短信服务SDK

系列专栏链接如下&#xff0c;方便跟进&#xff1a; https://blog.csdn.net/weixin_62588253/category_12821860.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12821860&sharereferPC&sharesourceweixin_62588253&sharefromfrom_link 同时篇幅…

A02、JVM性能监测调优

1、JVM内存模型 1.1、介绍 JVM 自动内存分配管理机制的好处很多&#xff0c;但实则是把双刃剑。这个机制在提升 Java 开发效率的同时&#xff0c;也容易使 Java 开发人员过度依赖于自动化&#xff0c;弱化对内存的管理能力&#xff0c;这样系统就很容易发生 JVM 的堆内存异常&…

钉钉调试微应用整理2

第一步 新建应用 钉钉开放平台](https://open-dev.dingtalk.com/) 去新增应用 第二步 配置应用信息 把本地代码运行起来&#xff0c;并设置本地地址 第三步 在本地代码添加调试命令 这里有2中添加方式 哪一种都可以 方式一&#xff1a; index.html页面中 <!DOCTYPE h…

《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列

《TCP/IP网络编程》学习笔记 | Chapter 3&#xff1a;地址族与数据序列 《TCP/IP网络编程》学习笔记 | Chapter 3&#xff1a;地址族与数据序列分配给套接字的IP地址和端口号网络地址网络地址分类和主机地址边界用于区分套接字的端口号数据传输过程示例 地址信息的表示表示IPv4…

飞牛fnOs内网穿透-使用Lucky实现ipv6动态解析+HTTPS访问NAS服务

&#x1f9ed;Lucky官方介绍 Lucky最初是作为一个小工具&#xff0c;由开发者为自己的个人使用而开发&#xff0c;用于替代socat&#xff0c;在小米路由AX6000官方系统上实现公网IPv6转内网IPv4的功能。Lucky的设计始终致力于让更多的Linux嵌入式设备运行&#xff0c;以实现或…

《安富莱嵌入式周报》第345期:开源蓝牙游戏手柄,USB3.0 HUB带电压电流测量,LCR电桥前端模拟,开源微型赛车,RF信号扫描仪,开源无线电收发器

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 本周更新一期视频教程 第5期&#xff1a;RTX5/FreeRTOS全家桶源码工程综合实战模板集成CANopen组件&#xff08;2024-1…

微服务中常用分布式锁原理及执行流程

1.什么是分布式锁 分布式锁是一种在分布式系统环境下实现的锁机制&#xff0c;它主要用于解决&#xff0c;多个分布式节点之间对共享资源的互斥访问问题&#xff0c;确保在分布式系统中&#xff0c;即使存在有多个不同节点上的进程或线程&#xff0c;同一时刻也只有一个节点可…

三:LoadBalancer负载均衡服务调用

LoadBalancer负载均衡服务调用 1.LB负载均衡(Load Balance)是什么2.loadbalancer本地负载均衡客户端 与 Nginx服务端负载均衡区别3.实现loadbalancer负载均衡实例3-1.首先应模拟启动多个服务提供者应用实例&#xff1a;3-2.在服务消费项目引入LoadBalancer3-3&#xff1a;测试用…

简单入门Git

Git作用 Git简介 作用&#xff1a;版本控制多人协作 集中式 典型代表&#xff1a;SVN 特点&#xff1a;所有的版本库都存在中央服务器&#xff0c;本地备份动作必须依赖中央服务器&#xff0c;如果一旦服务器挂掉&#xff0c;或者网络状况不好&#xff0c;没法提交版本。…

解决echarts桑基图为0时tooltip不显示的问题

关键代码 formatter: function (params) {console.log("params",params)if (params.value 0) {// 如果值为0&#xff0c;返回空字符串&#xff0c;不显示任何内容return params.name : params.value;// return ;} else {// 否则返回标准的格式化信息return par…

DevOps业务价值流:版本规划的最佳实践

初入公司&#xff0c;面对瀑布研发模式下的冗长周期与频繁返工&#xff0c;我率先尝试局部敏捷迭代&#xff0c;但成效有限。随后&#xff0c;推动全面敏捷化&#xff0c;从需求阶段即开始规划&#xff0c;虽方向正确&#xff0c;却遭遇版本规划难题。项目经理与产品经理对敏捷…

NewStar CTF 2024 misc WP

decompress 压缩包套娃&#xff0c;一直解到最后一层&#xff0c;将文件提取出来 提示给出了一个正则&#xff0c;按照正则爆破密码&#xff0c;一共五位&#xff0c;第四位是数字 ^([a-z]){3}\d[a-z]$ 一共就五位数&#xff0c;直接ARCHPR爆破&#xff0c;得到密码 xtr4m&…

2020年美国总统大选数据分析与模型预测

数据集取自&#xff1a;2020年&#x1f1fa;&#x1f1f8;&#x1f1fa;&#x1f1f8;美国大选数据集 - Heywhale.com 前言 对2020年美国总统大选数据的深入分析&#xff0c;提供各州和县层面的投票情况及选民行为的可视化展示。数据预处理阶段将涉及对异常值的处理&#xff0…

A Consistent Dual-MRC Framework for Emotion-cause Pair Extraction——论文阅读笔记

前言 这是我第一次向同学院同年级的学生和老师们汇报的第一篇论文,于2022年发表在TOIS上,属于CCF A类,主要内容是将MRC应用到情感原因对抽取中。 论文链接:用于情绪-原因对提取的一致双 MRC 框架 |信息系统上的 ACM Transactions 这里我就不放上我自己翻译的中文版还有我…

智慧公厕解决方案是未来厕所新建和改造的方向

在当今科技飞速发展的时代&#xff0c;智慧公厕解决方案正逐渐成为厕所新建和改造的主流方向&#xff0c;为人们带来更便捷、卫生、高效的使用体验。 一、智能化体验提升便捷性 智慧公厕配备了一系列智能设施&#xff0c;极大地提升了使用的便捷性。比如&#xff0c;智能环保取…

python爬取m3u8视频(思路到实现全讲解!!!)

文章目录 抓取m3u8视频1、思路分析2、实现分析index.m3u8 3、代码实现3.1 获取最后一个m3u8的url地址3.2 多线程下载ts文件与视频合并3.3 合并获取上面俩个代码段的代码 4、注意事项4.1 说明4.2 使用代码进行处理4.3 完整代码 5、解密处理 处理m3u8文件中的url问题 抓取m3u8视频…

“方块兽神仙猿点石成金”游戏搭建开发

“方块兽神仙猿点石成金”是一款结合了策略和运气的休闲游戏。玩家需在规定时间内向不同的山头投入矿石&#xff0c;等待神仙猿降临并随机选择一座山进行“点石成金”。根据神仙猿的选择&#xff0c;玩家将获得不同的奖励。 游戏核心机制 矿石投入&#xff1a;玩家在游戏开始…

Centos Linux 7 搭建邮件服务器(postfix + dovecot)

准备工作 1. 一台公网服务器&#xff08;需要不被服务商限制发件收件的&#xff0c;也就是端口25、110、143、465、587、993、995不被限制&#xff09;&#xff0c;如有防火墙或安全组需要把这些端口开放 2. 一个域名&#xff0c;最好是com cn org的一级域名 3. 域名备案&am…

二级列表联动

介绍 本示例主要介绍了List组件实现二级联动&#xff08;Cascading List&#xff09;的场景。 该场景多用于商品种类的选择、照片不同类型选择等场景。 效果图 使用说明&#xff1a; 滑动二级列表侧控件&#xff08;点击没用&#xff09;&#xff0c;一级列表随之滚动。&…