嵌入式软件--51单片机 DAY 2
一、数码管
1.数码管概况


2.设计
(1)硬件设计
我们可以通过阴极控制显示的位置,通过阳极控制显示的内容。两个数码管共有8个阴极引脚和16个阳极引脚,如果所有引脚都直接接入MCU,会造成MCU引脚的极大浪费。
为了节省MCU的引脚,我们可以将两个数码管的阳极接在一起。

如此我们就有了8个阴极,8个阳极16个引脚。我们只需通过8个GPIO引脚就能控制这8位数码管的显示内容了。
既然是八位,我们很快想到了38译码器,通过三位二进制数字的输入控制八种结果。


由于51单片高电平的驱动能力很微弱,不足以点亮数码管,因此可以使用74HC245N作为驱动芯片,该芯片的用法如下。

有了74HC245之后,51单片引脚的输出就只用作信号,而驱动数码管的电流则由74HC245的电源提供。


(2)软件设计
为了实现当前需求,需要考虑两点,分别是显示位置和显示内容。确定显示位置称为数码管的位选,确定显示内容称为数码管的段选。
1》位选
P13 P14 P15控制显示位置,连接数码管阴极,如果为0低电平就能导通显示。故控制位选。


P13接到了A0,P14接到了A1,P15接到了A2。
例:如果p15-p13输入为000,那么与y0相连的1号数码显示。
如果001,第二位显示
010,第三位显示
011,第四位显示
100,第五位显示
······
P17 P16 P15 P14 P13 P12 P11 P10
0 0 1 1 1 0 0 0
P1编码的中三位控制着位选。
2》段选
根据原理图可知,数码的段选通过单片机的P00~P07这7个引脚控制,具体的对应关系如下。
阳极连接。如果不点亮,给0即可。想显示,给1即可。

以上显示,代表着数字0,即给ABCDEF一个高电平1,G给0不亮,DP给0代表小数点不亮。
所以段选,P07(高位)--P01:0 0 1 1 1 1 1 1
那么可以给寄存器P0一个值0x3F.

通过p00-p07显示数码管的内容。通过让ABCDEFG、DP的亮灭,显示数字。
如此可以得到映射关系表:

3》代码实现
要求:静态显示,在任意位置,显示任意数字。
位选决定位置。根据位选的数位,决定P13~P15的取值。
段选,0~9的数字显示通过P00-P07控制。数字0要让ABCDEF亮起,如此编码就为:00111111
十六进制0x3F。数字2即为0x5B.
如果让数字在第一个位置亮起,P15~P13:0 0 0
段选好说,将数字编码2赋值于P0,2对应十六进制0X5B,即可通过控制数码管显示对应的数字。

位选需要动动脑筋,switch能够做到,但没有效率。我们用position形参,传递的是第几位。假设P1是定义的八位变量,P1=10 101 010,我们要在第4位显示数字,那么P15-P13:011 position:0000 0011,现在要做的就是将position的末三位赋值到P1的中三位,并不影响P1其他数位上的数字。
所以考虑怎样给到P1的中三位。
P1:10 101 010
position:0000 0 011
为了更好的观察规律,先将position左移三位。
P1:10 101 010
position:00 011 000
将P1的中三位置0,在与position做或运算。那么先让P1中三位置零,就与上11000111,其他几位都是1,1与任何数相与都是原来的数。
那么调整下方法:让position左移三位,让P1&11000111,在P1与position作或运算。
position<<=3;
P1&=11000111;//P1&=0xC7
p1|=position;
代码表示为:
#include <STC89C5xRC.H>
#define SMG_EN P36 // 数码管总开关
#define LED_EN P34 // LED灯总开关
typedef unsigned char u8; // 给无符号字符类型取别名,代表无符号8位
static u8 s_digit_codes[10] = {0x3F, // 00x06, // 10x5B, // 20x4F, // 30x66, // 40x6D, // 50x7D, // 60x07, // 70x7F, // 80x6F // 9
};//编码数组
//定义函数
void DigitalTube_DisplaySingle(u8 position, u8 num_code)//一个参数位选:P13/P14/P15,一个参数段选
{P1 &= 0xC7;//按位与运算position <<= 3;P1 |= position;P0 = num_code;//数字编码赋予P0
}
void main()
{// 打开数码管总开关SMG_EN = 0;// 关闭LED灯总开关LED_EN = 0;DigitalTube_DisplaySingle(0, s_digit_codes[2]);//让数字显示在位选0第一个位置,显示内容为2while (1) {};
}
烧录以上代码到51核心板内,数码管第一个位置显示2就完成了。
4》变量声明
在C89标准中,所有声明的变量必须在作用域的最前边声明。C99就没有这个约束了。注意一下即可!
二、数码管动态显示
1.要求

我们先搞整数的显示。
2.设计
8位数码管同一时刻只能显示一个位置,通过高速的循环显示可以做到以上效果。
(1)思路

(2)代码实现
我们首先要定义一个显存数组。
#include <STC89C5xRC.H>
#define SMG_EN P36 // 数码管总开关
#define LED_EN P34 // LED灯总开关
typedef unsigned char u8; // 给无符号字符类型取别名,代表无符号8位
typedef unsigned long u32;
static u8 s_digit_codes[10] = {0x3F, // 00x06, // 10x5B, // 20x4F, // 30x66, // 40x6D, // 50x7D, // 60x07, // 70x7F, // 80x6F // 9
};//编码数组
//定义显存数组
u8 buffer[8];
//定义函数
void DigitalTube_DisplaySingle(u8 position, u8 num_code)//一个参数位选:P13/P14/P15,一个参数段选
{P0=0x00;P1 &= 0xC7;//按位与运算position <<= 3;P1 |= position;P0 = num_code;//数字编码赋予P0
}
//设置显存数组,待展示数字
void DigitalTube_DisplayNum(u32 num)
{u8 i;for(i=0;i<8;i++){
buffer[i]=0x00;}//将数组内元素都初始化if (num==0){buffer[7]=s_digit_codes[0];return;}i=7;while (num>0){buffer[i]=s_digit_codes[num%10];num/=10;i--;}}
//动态扫描
void DigitalTube_Refresh()
{
u8 i;
for ( i = 0; i < 8; i++)
{DigitalTube_DisplaySingle(i,buffer[i]);
}}
void main()
{// 打开数码管总开关SMG_EN = 0;// 关闭LED灯总开关LED_EN = 0;DigitalTube_DisplayNum(12345);while (1) {DigitalTube_Refresh();};
}
上图的效果就实现了。
(3)实现负数
负数的表示编码为0x40,将之作为段选数组的最后一位,codes【10】。
Int_Digital.c
#include <STC89C5xRC.H>
#include "Int_DigitalTube.h"
#include "Com_Util.h"
//定义段选内容编码
static u8 codes[11]={0x3F,//00x06,//10x5B,//20x4F,//30x66,//40x6D,//50x7D,//60x07,//70x7F,//80x6F,//90x40//负号
};
//定义显存数组
static buffer[8];
//开关启动
void Int_DigitalTube_Init()
{SMG_EN=0;LED_EN=0;
}void Int_DigitalTube_DisplaySingle(u8 dig, u8 num)
{P0=0x00;P1&=0xC7;dig<<=3;P1|=dig;P0=num;
}void Int_DigitalTube_Displaynum(long num)
{
u8 i;
for(i=0;i<8;i++)
{buffer[i]=0x00;
}
if(num==0)
{buffer[7]=codes[0];return;
}
if(num<0)
{num=-num;i=7;while(num>0){buffer[i]=codes[num%10];num/=10;i--;}buffer[i]=codes[10];Com_Util_Delay1ms(1);
}else
{i=7;while(num>0){buffer[i]=codes[num%10];num/=10;i--;Com_Util_Delay1ms(1);}
}}void Int_DigitalTube_Refresh()
{u8 i;for(i=0;i<8;i++){Int_DigitalTube_DisplaySingle(i,buffer[i]);}
}
main.c
#include <STC89C5xRC.H>
#include "Com_Util.h"
#include "Int_DigitalTube.h"
void main()
{Int_DigitalTube_Init();Int_DigitalTube_Displaynum(-1235);while(1){Int_DigitalTube_Refresh();}
}
三、模块化编程
随着我们的代码越来越复杂,我们的main.c越来越长,阅读性也越来越差。如果将来开始做项目,我们可能要同时操作好几个模块,这种情况下我们无法再把代码写到同一个文件,而是要分模块管理代码。具体实现方法,就是将源码按照不同功能和模块,拆成若干部分源码,再用头文件相互引用。
1.命名规范
变量命名
函数命名
文件命名
2.代码分层规范
(1)目录
(2)驱动层
所有与芯片直接交互的自身硬件代码,例如GPIO开关、硬件UART/ADC的驱动、计时器等。
目录:Dri/
前缀:Dri_
(3)接口层
位于驱动层之上,通过标准接口驱动的外部硬件代码,没有外部硬件设备,可以不用这一层。
目录:Int/
前缀:Int_
(4)中间层
提供更高级的服务,如操作系统、文件系统、通信协议栈等。
简单项目用不到这一层。
目录:Mid/
前缀:Mid_
(5)应用层
包含应用程序的主要逻辑。实现与上层交互,不直接访问这一层。
目录:App/
前缀:App_
3.创建项目模板
为方便后续项目的创建,可以创建一个基础模板,后边项目全部基于模板创建。
(1)创建一个新的项目,取名为模板。

(2)配置项目


(3)项目规范结构

(4)编写通用代码
Com_Util.c
#include "Com_Util.h"
#include <INTRINS.H>void Com_Util_Delay1ms(u16 count)
{u8 i, j;while (count > 0) {count--;_nop_();i = 2;j = 199;do {while (--j);} while (--i);}
}
Com_Util.h
#ifndef __COM_UTIL_H__
#define __COM_UTIL_H__typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;void Com_Util_Delay1ms(u16 count);#endif // !1

(5)导出模板


下次使用本地模板点开ept文件即可。

相关文章:
嵌入式软件--51单片机 DAY 2
一、数码管 1.数码管概况 2.设计 (1)硬件设计 我们可以通过阴极控制显示的位置,通过阳极控制显示的内容。两个数码管共有8个阴极引脚和16个阳极引脚,如果所有引脚都直接接入MCU,会造成MCU引脚的极大浪费。 为了节省…...
高精度加法,减法,乘法,除法
加法: 大整数该如何储存? 用数组储存: 把个位放在数下标为0的位置,十位放在数组下标为1的位置(也就是高位放在数组的后面) 因为这样,如果需要增加一位最高位,那我们就可以直接在…...
学习计划(大三上)
第二周 总结Java并发编程的艺术 学习JVM(博客文章) 第三周 学习JVM(博客文章) 图解TCP/IP 4章 第四周 完成简历项目 学习JVM(博客文章) 图解TCP/IP 4章 第五周 完成简历项目 深入学习RocketMQ底层…...
【第0006页 · 数组】寻找重复数
【前言】本文以及之后的一些题解都会陆续整理到目录中,若想了解全部题解整理,请看这里: 第0006页 寻找重复数 今天想讨论的一道题在 LeetCode 上评论也是颇为“不错”。有一说一,是道好题,不过我们还是得先理解了它才…...
移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——10.继承
1.继承的概念及定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保 持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象 程序设计的层…...
uniapp+vue3实现双通道透明MP4播放支持小程序和h5
双通道透明MP4视频播放的截图 以下是合成后结果,二个合并在一起进行播放 下载资源,打开运行直接使用看到效果 https://download.csdn.net/download/qq_40039641/89715780...
汇编:嵌入式软件架构学习资源
成为嵌入式软件架构设计师需要掌握多方面的知识,包括嵌入式系统、实时操作系统、硬件接口、软件设计模式等。 以下是一些推荐的博客和网站,可以帮助你深入学习嵌入式软件架构设计: ### 1. **Embedded.com** - **网址**: [Embedded.com](htt…...
python编程知识(实现数据加密和解密)
👨💻个人主页:开发者-曼亿点 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 曼亿点 原创 👨💻 收录于专栏:…...
如何使div居中?CSS居中终极指南
前言 长期以来,如何在父元素中居中对齐一个元素,一直是一个让人头疼的问题,随着 CSS 的发展,越来越多的工具可以用来解决这个难题,五花八门的招式一大堆,这篇博客,旨在帮助你理解不同的居中方法…...
Redis 篇-深入了解分布式锁 Redisson 原理(可重入原理、可重试原理、主从一致性原理、解决超时锁失效)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 本章目录 1.0 基于 Redis 实现的分布式锁存在的问题 2.0 Redisson 功能概述 3.0 Redisson 具体使用 4.0 Redisson 可重入锁原理 5.0 Redisson 锁重试原理 6.0 Redisson WatchDo…...
PostgreSQL中的多版本并发控制(MVCC)深入解析
引言 PostgreSQL作为一款强大的开源关系数据库管理系统,以其高性能、高可靠性和丰富的功能特性而广受欢迎。在并发控制方面,PostgreSQL采用了多版本并发控制(MVCC)机制,该机制为数据库提供了高效的数据访问和更新能力…...
SpringBoot项目-实现简单的CRUD功能和分页查询
背景 本博文主要是创建了一个新的SpringBoot项目,实现基本的增删改查,分页查询,带条件的分页查询功能。是方便初学者学习后端项目的一个比较清晰明了的实践代码,读者可根据博文,从自己动手创建一个新的SpringBoot项目…...
CCF编程能力等级认证GESP—C++2级—20240907
CCF编程能力等级认证GESP—C2级—20240907 单选题(每题 2 分,共 30 分)判断题(每题 2 分,共 20 分)编程题 (每题 25 分,共 50 分)数位之和小杨的矩阵 单选题(每题 2 分,共…...
C语言手撕实战代码_二叉排序树(二叉搜索树)_构建_删除_插入操作详解
二叉排序树习题1.设计算法构建一棵二叉排序树(又称二叉搜索树BST)2.查找二叉排序树中结点为x的结点所在的层数3.删除二叉排序树T中值为x的结点4.查找二叉排序树中所有小于key的关键字5.编写算法,将一棵二叉树t分解成两棵二叉排序树t1和t2,使得t1中的所有…...
YC教父的创始人模式VS职业经理人模式:AI时代的独立开发者崛起
近年来,由风投资助的创始人模式因其相对较低的入门门槛而在创业圈内广受欢迎。然而,真正的挑战在于独立开发者(一人商业)模式。随着AI技术的飞速发展,一人商业模式有望成为未来的主流。本文将探讨独立开发者的工作范围…...
[SUCTF 2019]Pythonginx
给了源码 app.route(/getUrl, methods[GET, POST]) def getUrl():url request.args.get("url")host parse.urlparse(url).hostnameif host suctf.cc:return "我扌 your problem? 111"parts list(urlsplit(url))host parts[1]if host suctf.cc:retu…...
省市县相关校验sql随笔
1.层级校验 要判断一个给定的省、市、区(县)名字是否符合正确的层级关系,假设你的表结构如下: CREATE TABLE regions (id INT PRIMARY KEY,name VARCHAR(255),parent_id INT, -- 指向上一级区域的id,例如市的parent_id指向省的…...
uniapp ios sticky定位,内部 u-tabs(包含scroll-view)消失问题
uniapp中用sticky定位时,元素内部如果有scroll-view,ios在触发bounce机制时,scroll-view的元素会消失,解决方法是页面上包一层高度为100vh的scroll-view <scroll-view style"height: 100vh;" scroll-y scrolltolowe…...
web群集--nginx配置文件location匹配符的优先级顺序详解及验证
文章目录 前言优先级顺序优先级顺序(详解)1. 精确匹配(Exact Match)2. 正则表达式匹配(Regex Match)3. 前缀匹配(Prefix Match) 匹配规则的综合应用验证优先级 前言 location的作用 在 NGINX 中࿰…...
Vivado编译报错黑盒子问题
1 问题描述 “Black Box Instances: Cell **** of type ** has undefined contents and is considered a back box. The contents of this cell must be defined for opt_design to complete successfully.” 检查工程代码提示的模块,该模块为纯手写的Veril…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
