找回密码
 立即注册
查看: 6704|回复: 33

STC32G12K128 成长道路

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-24 08:42:40 | 显示全部楼层 |阅读模式
本帖最后由 t176 于 2023-4-27 08:46 编辑

Lesson 1

开篇:
LINK1D 仿真:




1.首先,仿真线路的连接;
屠龙刀:
屠龙刀接线.png
2.目标芯片与STC LINK1D硬件仿真器通过或SWD接口连接(P3.0,P3.1),以建立仿真通讯链路;
链路1.jpg


3.在keil进行参数配置,以及ISP设置仿真芯片
详细方法,请参考STC32G.PDF  5.11章节和5.12章节.(****必看,根据手册内容进行配置)
Page135-151.

查阅手册.png


PDF下载:
PDF下载.png

请注意:如果在ISP中设置为仿真芯片,没设置端口和SWD,将仿真失败
设置仿真芯片.png
4.编写并编译代码,生成HEX文件
测试代码.png
5.通过STC_ISP,将生成的可烧录指令文件下载到STC LINK1D硬件仿真器中的处理器内存区域,作为仿真器内部的程序;
烧录完成.png

6.启动keil调试功能,在仿真器和目标芯片之间建立仿真操作链路;


启动仿真功能.png
7. LINK1D仿真操作过程中,通过LINK1D与PC之间的通讯,将LINK1D内部的程序烧录进目标芯片中.
下载.png

8.keil调试工具可以实时地显示芯片内部状态信息.比如查看某一个变量的值,或是切换到代码窗口查看此时程序的执行位置;实现目标芯片的单步调试、断点调试、变量跟踪等功能,方便用户对复杂程序进行调试。


打开窗口.png

内部信息.png
















喜欢研究如何让电子产品变得更加智能和有趣.
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-24 08:42:41 | 显示全部楼层
本帖最后由 t176 于 2023-4-21 16:07 编辑

Lesson 2

5分钟理解进制存储机制,IO口:(相关理论知识,可通过百度查询,这里只做仿真效果下的学习)

IO口是单片机用来控制外部设备的一组通用输入/输出接口,
IO口 可以配置为4种模式:

准双向口:传统8051端口模式,弱上拉.灌电流可达20mA,拉电流为270150μA(存在制造误差)

推挽输出:强上拉输出,可达20mA,要加限流电阻


高阻输入:电流既不能流入也不能流出


开漏输出:内部上拉电阻断开开漏模式既可读外部状态也可对外输出(高电平或低电平)。如要正确读外部状态或需要对外输出高电平,需外加上拉电阻,否则读不到外部状态,也对外输不出高电平。

准双向模式:准双向IO口是一种介于输入和输出之间的模式,它可以在不改变端口的输入/输出状态的情况下,切换IO口的方向。这种模式常用于I/O总线和共享总线设备的控制。


开漏/推挽模式:开漏模式和推挽模式是输出模式的两种变体。在开漏模式下,输出端口只能输出低电平或不输出电平;而在推挽模式下,输出端口可以输出高电平或低电平。这两种模式常用于将多个输出口连接到同一总线上,从而实现集中控制。


目前学习我们先用准双向IO口进行配置学习,后期应用案列中会逐步介绍其他模式
4种模式的定义可以参考PDF 11章 Page 293 或者直接使用ISP 生成配置代码

IO配置.png


通过编程控制IO口的高低电平状态,就可以实现对外部设备的控制。
32G  IO口的引脚图:
根据封装工艺的需求,芯片在生成时,有多种封装规格 下面是LQFP的封装样式,


引脚图.png

当然还有其他样式,在ISP 中可以查阅观察.
引脚封装.png

通过引脚的观察 我们看到 有一组P开头的引脚0-7,这就是IO口.
通常IO 口 一组为八个. 0-7 列如 P0.1-P0.7
他们在内存中形态以十六进制存储(00-FF).单个IO口则是二进制存储(0-1)
8个二进制位 组成二个十六进制的存储单元


如果还是理解不太明白.没关系,接下来使用一个仿真程序带你窥视内存.







下面是一份简单的代码,你不需要对他进行理解.我们这里只用作于仿真,强化学习进制和IO 的知识点.

  1. #include <STC32G.H>
  2. void main()
  3. {
  4.     EAXFR = 1;    // 使能访问 XFR
  5.     CKCON = 0x00; // 设置外部数据总线速度为最快
  6.     WTST = 0x00;  // 设置程序代码等待参数,
  7.     // 赋值为 0 可将 CPU 执行程序的速度设置为最快
  8.     P0M0 = 0x00;
  9.     P0M1 = 0x00;
  10.     P1M0 = 0x00;
  11.     P1M1 = 0x00;
  12.     P2M0 = 0x00;
  13.     P2M1 = 0x00;
  14.     P3M0 = 0x00;
  15.     P3M1 = 0x00;
  16.     P4M0 = 0x00;
  17.     P4M1 = 0x00;
  18.     P5M0 = 0x00;
  19.     P5M1 = 0x00;
  20.     while (1)
  21.     {
  22.        P25=~P25;//翻转电平
  23.     }
  24.    
  25. }
复制代码


我们先对这段代码进行仿真:


在单片机中,常用的进制有二进制、十进制和十六进制。

当你顺利进入仿真 你看到的keil 界面是这样的
默认界面.png


我们可以看到
1 是命令执行执行窗口
2 是监视区域



我们为了实时观察变量 建议打开变量监视 按照步骤执行第3步 和第四部
变量监视.png


点开 监视表1 我们就能看到 有三个字段
NAME VALUE  TYPE
NAME: 表达式
VALUE:值
TYPE:类型

在这里我们可以根据编辑特有的表达式 进行内容观察
表达式计算.png


图中我们可以看到  使用表达式 可以直接进行计算,好了,基础的仿真 就讲到这里.我们接下来 IO口(数值)在内存是存储状态

我们打开内存窗口

内存.png

我们在内存地址中输入&P2
为什么要加&,&是取地址,
我们可以看到内存中的存储单元都是 以16进制展示的(00-FF).这个FF 就是存储了 8个二进制位  既P2(IO口组合)
那么我们如何理解IO口是二进制状态呢,接下来看这张图
IO口.png

当点击完成后我们就可以看到一个IO口的 具体二进制存储  情况
IO口监视器.png

7-0 Bits 存储了 P2_IO口组的 IO状态 .
打勾的表示1  如果没勾 就会变成0;
现在你可以尝试下 点击这些勾选 对比 前面16进制的 变化.
IO口操作.png


通过点击,你会发现  前面的16进制数值也跟着相应的变化,同时可以观察 内存区域或者变量监视表会跟着变化
那么我们就明白了,一个IO口存储一个二进制(0-1) 一个十六进制(0-F)存储着 4个IO口的二进制状态.FF所以可以存储8个IO口.到这里我相信你对进制的内存存储已经有一个 新的认识.

接下来,请点击勾选观察单片机的LED亮灭状态
点了没变化啊,咋回事?

别着急 因为代码IO口配置没有  初始化 你没执行


单步调试.png

我们可以选择快捷键F11 进行执行单步调试,在代码执行完20行,那么所以的IO 口初始化代码都已经初始化完毕.现在你再点击试试.

你会发现 你点击一个IO口,开发板上的LED就会产生相应的亮灭变化.

亮灭变化.png
板子亮灭情况.jpg


根据上面的试验,我们学习了 进制的存储状态,和IO口的概念.以及仿真的基本操作.
相信你对进制存储以及转换有了更直观的认识.


并且发现仿真器 对仿真芯片拥有实时的控制权和监视能力.那么在后面的开发中,相当于给程序员一只眼睛,在接下来的学习中.会开始写代码,这个过程中,使用仿真去调试会事半功倍.

现在问题来了...............

问题1:
硬件仿真模式下,LINK1D 是不是对32G有绝对控制权?


从理想状态上来说,是可以的.但是考虑到仿真环境中可能存在的各种干扰因素

(自然因素干扰)
例如噪声、时钟波形失真等因素,这些都可能会影响LINK1D对目标单片机的控制能力。
(人为因素干扰)
如果开发者在仿真过程中,对寄存器进行错误的修改,导致仿真链路的破坏.

LINK1D将不能完全地控制和解决这些问题.


问题2:
为什么IO口变成0  LED就会点亮?变成1为什么又熄灭.

这就引出我们下一课学习,如何点亮一个LED灯,原理是什么,如何编写相应的代码?







喜欢研究如何让电子产品变得更加智能和有趣.
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-24 08:42:42 | 显示全部楼层
本帖最后由 t176 于 2023-4-22 10:31 编辑

Lesson 3
编写第一个程序,点亮LED(以及寄存器的认识)
屠龙刀在出厂的时候默认P2端口焊接了电阻和绿光LED灯
LED电路.png

图中
1为VCC
2为贴片发光二极管   
3限流电阻


电路分析:
电流经过VCC(1)----->发光二极管(2)----->限流电阻---->IO口
当IO口状态为0时,IO口处于低电平状态 整个电流流通,LED点亮
当IO口状态为1时,IO口处于高电平状态.根据电气特性,LED熄灭
限流电阻的作用:
图中使用5.1K 的限流电阻,限制电路中电流大小,从而保护led,可以延长led的寿命.


明白了LED的亮灭,可以根据条件 编写相应代码 ,点亮LED


编写代码:

  1. #include <STC32G.H>
  2. sbit LED = P2 ^ 5; // 位定义,将LED 变量 定义为P2口的第5个引脚
  3. void main()
  4. {
  5.     EAXFR = 1;    // 使能访问 XFR
  6.     CKCON = 0x00; // 设置外部数据总线速度为最快
  7.     WTST = 0x00;  // 设置程序代码等待参数,
  8.     // 赋值为 0 可将 CPU 执行程序的速度设置为最快
  9.     P0M0 = 0x00;
  10.     P0M1 = 0x00;
  11.     P1M0 = 0x00;
  12.     P1M1 = 0x00;
  13.     P2M0 = 0x00;
  14.     P2M1 = 0x00;
  15.     P3M0 = 0x00;
  16.     P3M1 = 0x00;
  17.     P4M0 = 0x00;
  18.     P4M1 = 0x00;
  19.     P5M0 = 0x00;
  20.     P5M1 = 0x00;
  21.     LED = 0; // LED控制引脚为低电平
  22.     while (1)
  23.     {
  24.     }
  25. }
复制代码

代码拆解:
sbit  是什么
sbit  是 Keil C编译器中的一种语法.用于访问单个位(bit)。在使用sbit语法时,需要指定需要访问的位所在的寄存器和位的位置.


P2又是什么? 在STC32G.H头文件中
sfr P2 = 0xa0;
原来P2是个寄存器.
P2^5 是什么.表示访问寄存器的第5位.

LED=0; 将是将引脚赋予低电平.

拓展内容:

那么现在是不是 对寄存器也有了一个初步的认识.简言之,P2 其实就是在STC32G.H绑定了莫个寄存器.弄明白这个问题,你可以自己定义自定义IO口将其绑定在特定的寄存器上,从而使编程更加灵活.
寄存器.png


点亮一组LED
在上面的教程中,我相信你已经学会了 如何点亮一个led,那么如何点亮一组LED呢?
还记得之前学的吗 ,一个内存单元(二个十六进制) 组成 8个IO口(二进制位),只要简单的转换下就好了
我们进入仿真来学习

IO组.png

我们随便取消掉几个勾选,也就是说给这几个端口赋予低电平.期望点亮这些IO口
得到了一个十六进制 CE ,我们将它转换成二进制试试
最简单的方法当然是使用 WINDOWS 自带的 计算器了
计算器1.png


然后我们去代码实现下.

  1. #include <STC32G.H>
  2. void main()
  3. {
  4.     EAXFR = 1;    // 使能访问 XFR
  5.     CKCON = 0x00; // 设置外部数据总线速度为最快
  6.     WTST = 0x00;  // 设置程序代码等待参数,
  7.     // 赋值为 0 可将 CPU 执行程序的速度设置为最快
  8.     P0M0 = 0x00;
  9.     P0M1 = 0x00;
  10.     P1M0 = 0x00;
  11.     P1M1 = 0x00;
  12.     P2M0 = 0x00;
  13.     P2M1 = 0x00;
  14.     P3M0 = 0x00;
  15.     P3M1 = 0x00;
  16.     P4M0 = 0x00;
  17.     P4M1 = 0x00;
  18.     P5M0 = 0x00;
  19.     P5M1 = 0x00;
  20.     P2 =0XCE;//将16进制数组赋值给P2寄存器,直接操控8个LED灯
  21.     while (1)//这是一个空循环,阻断程序继续执行,如果不加while 根据单片机的特性,main函数 在执行完毕后
  22.     {
  23.     }
  24. }
复制代码

XX1.jpg

通过本章的学习 我相信你已经学会 如何点亮一个IO 和点亮一组IO,并且对寄存器 有了一定的了解.那么问题来了

问题1:
我想让LED 实现闪烁的效果,那应该如何去做?

这将引出下面一章  Delay 函数的使用...





喜欢研究如何让电子产品变得更加智能和有趣.
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-24 08:42:43 | 显示全部楼层
本帖最后由 t176 于 2023-4-23 11:27 编辑

Lesson 4


Delay函数的使用,第一次使用寄存器
上一章中,我们提出一个问题,如果使用Delay 函数 进行LED的闪烁

首先我们整理下思路:
LED 的闪烁他的步骤应该是怎么样的?
LED灯亮---->LED灭----->LED灯亮---->LED灭
是不是这样一个执行过程,但是如果没有时间间隔,单片机的亮灭速度非常快,我们的肉眼是无法捕捉到.
那么有什么办法可以延迟LED的亮灭操作呢?
什么是延迟.
延迟顾名思义就是让计算机等下再执行下一条命令.
那么计算机如何让他等待呢?
我们可以嵌套一些循环代码,让单片机执行这些没有意义的代码,因为这些代码的执行需要时间,我们只要让他执行足够多的无用代码就能达到我们程序延时的 预期.
那么我们应该如何确定需要执行多少 无效代码呢.
STC_ISP 已经帮你做好了 你只要选下参数点下按钮就可以生成代码 .是不是很贴心.

软件延时.png


只要简单的设置下参数,他就能生成C语言或者汇编代码.
注意.png

看到注意事项没,WTST需要初始化00H(这将是我们接触的第一个寄存器)
00H:H 表示16进制 00H 也就是十六进制的0X00
那么WTST是什么呢,他是一个寄存器定义:
先看头文件:
sfr WTST = 0xe9;
当我们遇到不知道,不清楚的寄存器定义,务必先查手册,官方的手册最核心的内容之一就是寄存器的解释和使用方法.
为了方便编程,我已经将相关的头文件寄存器 翻译成中文 发布在STC 官网上,你也可以直接拿来替代 官方默认的头文件STC32G.H

https://www.stcaimcu.com/forum.php?mod=viewthread&tid=1288

WTST.png

  1. #include <STC32G.H>
  2. void Delay500ms()                //@11.0592MHz
  3. {
  4.         unsigned long i;
  5.         _nop_();
  6.         _nop_();
  7.         i = 1382398UL;
  8.         while (i) i--;
  9. }
  10. void main()
  11. {
  12.     EAXFR = 1;    // 使能访问 XFR
  13.     CKCON = 0x00; // 设置外部数据总线速度为最快
  14.     WTST = 0x00;  // 设置程序代码等待参数,// 赋值为 0 可将 CPU 执行程序的速度设置为最快
  15.     P0M0 = 0x00;
  16.     P0M1 = 0x00;
  17.     P1M0 = 0x00;
  18.     P1M1 = 0x00;
  19.     P2M0 = 0x00;
  20.     P2M1 = 0x00;
  21.     P3M0 = 0x00;
  22.     P3M1 = 0x00;
  23.     P4M0 = 0x00;
  24.     P4M1 = 0x00;
  25.     P5M0 = 0x00;
  26.     P5M1 = 0x00;
  27.     while (1)//这是一个空循环,阻断程序继续执行,如果不加while 根据单片机的特性,main函数 在执行完毕后
  28.     {
  29.                 Delay500ms();
  30.                 P25=~P25;
  31.     }
  32. }
复制代码

代码中
P25=~P25;
~是取反的运算符,
如果说P25 是高电平 那么就让他变成低电平.反之低电平变成高电平.




那么通过这章,我们已经学会了,如何控制一个IO口的高低电平,达到LED闪烁的目的.
这只是一个最简单的LED闪烁,程序.单片机能做的远远不止如此,比如我们需要实现一个花式点灯.那么应该如何去做呢?
下集我们将编写这个程序.






喜欢研究如何让电子产品变得更加智能和有趣.
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-24 08:42:44 | 显示全部楼层
本帖最后由 t176 于 2023-4-24 08:45 编辑

Lesson 5


实现一个花式流水灯


  1. #include <STC32G.H>
  2. #define LIGHT_COUNT 8 // LED 数量
  3. void Delay500ms() //@11.0592MHz
  4. {
  5.   unsigned long i;
  6.   _nop_();
  7.   _nop_();
  8.   i = 1382398UL;
  9.   while (i)
  10.     i--;
  11. }
  12. void main()
  13. {
  14.   unsigned char pattern[LIGHT_COUNT] = {
  15.       0x01, // 0000 0001 b
  16.       0x02, // 0000 0010 b
  17.       0x04, // 0000 0100 b
  18.       0x08, // 0000 1000 b
  19.       0x10, // 0001 0000 b
  20.       0x20, // 0010 0000 b
  21.       0x40, // 0100 0000 b
  22.       0x80  // 1000 0000 b
  23.   };            // LED 点亮模式
  24.   EAXFR = 1;    // 使能访问 XFR
  25.   CKCON = 0x00; // 设置外部数据总线速度为最快
  26.   WTST = 0x00;  // 设置程序代码等待参数,// 赋值为 0 可将 CPU 执行程序的速度设置为最快
  27.   P0M0 = 0x00;
  28.   P0M1 = 0x00;
  29.   P1M0 = 0x00;
  30.   P1M1 = 0x00;
  31.   P2M0 = 0x00;
  32.   P2M1 = 0x00;
  33.   P3M0 = 0x00;
  34.   P3M1 = 0x00;
  35.   P4M0 = 0x00;
  36.   P4M1 = 0x00;
  37.   P5M0 = 0x00;
  38.   P5M1 = 0x00;
  39.   while (1)
  40.   {
  41.     int i;
  42.     // 反向点亮每个 LED
  43.     for (i = LIGHT_COUNT - 1; i >= 0; i--)
  44.     {
  45.       P2 = ~pattern[i]; // 控制 LED 灯亮灭
  46.       Delay500ms();
  47.     }
  48.     // 轮流两个 LED 交替点亮
  49.     for (i = 0; i < LIGHT_COUNT - 1; i++)
  50.     {
  51.       P2 = ~(pattern[i] | pattern[i + 1]); // 控制 LED 灯亮灭
  52.       Delay500ms();
  53.     }
  54.     // 轮流两个 LED 交替点亮(2)
  55.     for (i = 7; i >= 0; i--)
  56.     {
  57.       P2 = ~(pattern[i] | pattern[i - 1]); // 控制 LED 灯亮灭
  58.       Delay500ms();
  59.     }
  60.     // 依次点亮每个 LED
  61.     for (i = 0; i < LIGHT_COUNT; i++)
  62.     {
  63.       P2 = ~pattern[i]; // 控制 LED 灯亮灭
  64.       Delay500ms();
  65.     }
  66.   }
  67. }
复制代码


在这个代码中分别实现了 LED 流水灯,和LED拖尾灯,当然如果你想让LED效果更炫酷可以,再进一步优化,这里只做简单学习.

代码中我们第一次接触到了|  这个按位运算,
P2 = ~(pattern | pattern[i - 1]);

代码中 | 的 作用    将这两个数进行合并,

~我们之前已经学过了,  这里将合并计算后的结果,进行取反.

在intrins.h 头文件 也有封装好的函数来实现我们所需的功能,但是前期我们少用,甚至不用.
尽量使用位运算符,使用娴熟后.可以让代码变得很精简干练.

好了这章就先到这里,留意下数组的写法,下一章数码管学习,我们会使用类似的写法

一定要理解掌握相关的知识点,这一章其实没多少知识点,重点是要善于思考,尝试自己去写一个炫酷的花式点灯效果.




下一章,我们将接触数码管.



喜欢研究如何让电子产品变得更加智能和有趣.
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-24 11:10:34 | 显示全部楼层
本帖最后由 t176 于 2023-5-2 20:13 编辑

Lesson 6


数码管的原理

昨天刚好收到官方邮寄的STC试验箱9.6.这就刚好排上用场了.本来打算数码管部分使用,89开发板制作教程.试验箱来的很及时啊

拿到硬件第一件事,就是先看原理图.如果没有原理图的就追板.
拓展知识:
追板的手法是强光打底,勾出线路,然后抄板.蚀刻,钻孔,清洗....在这里不做多的介绍 因为STC 已经提供了完整的原理图,和PCB 图 .对于我们学习已经完全足够了.


试验箱.jpg


原理图:
PCB.jpg 原理图.jpg

让我们跟着,官方的原理图开始学习把.




图1

数码管接线图.jpg
图2

IC引脚.jpg
图3

COMSS8550.jpg


数码管:(基础知识)
数码管是一种用来显示数字和某些特殊符号的电子器件,通常由七个或更多个发光二极管组成。每个发光二极管被排列在一个固定的位置上,以便按照要求显示数字和字符。


段的概念:每个数码管通常有七个以及七个以上发光二极管,用于显示数字 0 到 9 和一些字母。这些发光二极管组成一个显示单元被称为“段”

数码管.png

位的概念:为了显示多个数字或字母,需要使用多个数码管。在多个数码管中,每个数码管被称为“位”.列如实验箱中9.6 所用的元件就是2个4位的数码管,当然比较常见的 有1/2/3/4  位数码管


多位数码管.png







共阳极和共阴极:

数码管的共阴和共阳是指数码管的引脚连接方式。
在共阴数码管中,所有段的阴极(负极)都连接在一起,而每个段的阳极(正极)都分别连接到不同的引脚上。
共阴极接法,所有的数码管共享一个阴极,而每个发光二极管的阳极通过转换器单独控制。因此,为了点亮某个数字或符号,必须将相应的阳极接到高电平,而将公共阴极连接到低电平。




在共阳数码管中,所有段的阳极都连接在一起,而每个段的阴极都分别连接到不同的引脚上。

在共阳极接法,所有的数码管共享一个阳极,而每个发光二极管的阴极通过转换器单独控制。因此,为了点亮某个数字或符号,必须将相应的阴极接到低电平,而将公共阳极连接到高电平。

在试验箱9.6中,数码管使用的 共阳BS,当然还有一种是共阴AS.(本人非常有幸,在试验箱中同时体验了一波AS,和BS ).这是是一个心塞的故事....



仔细观察 图1/2/3中的 原理图
我们看到数码管的引脚连接,引脚相连在P6组上,并且看到位选连接在网络标识COM0-COM7 连接到了P7组


点亮数码管
学习完数码管的基础知识后.先将数码管当成普通发光二极管去使用. 那么我们如何点亮某位数码管中的一个LED(段):

点亮数码管.png

在这个数码管中,我们需要点亮改段中F通道,那么应该怎么做呢?

我们回过来参考图1中的原理图

段原理.png

我们发现,他接在单片机的P65 IO口上.现在知道 一组数码管的F通道了,那么如何让他点亮第一位  数码管的 F通道呢?,
那么你必须彻底弄清楚位选的概念.
在原理图中,我们看到有K1-K4的  4个引脚,没错!那就是 位选.相应的引脚参考图3(IO口则以SS850 为媒介实现以小推大,将VCC电源放行到数码管位选端口
)

位原理图.png

下面是 代码实现点亮 第一位数码管的F通道.

  1. #include <STC32G.H>
  2. void main()
  3. {
  4.     P6M0 = 0x00;
  5.     P6M1 = 0x00;
  6.     P7M0 = 0x00;
  7.     P7M1 = 0x00;
  8.     P7 = 0x7F; //01111111 B
  9.     P6 = 0xDF;//11011111 B
  10.     while (1)
  11.     {
  12.         
  13.    
  14.     }
  15. }
复制代码
实验现象:

实验现象.jpg

请尝试思考下代码中 P7 和P6 的取值原理,如果弄明白,那么恭喜你,数码管你已经学会了一大半了.如果没弄明白,没关系,我们下一章 静态显示和动态扫描中,会详细讲解,段码 ,位码.



课外话:
根据有关部门,相关人士透露我手上这张板子是测试用的错版,在自己动手 修复完板子错版问题:数码管AS---->BS,经过测试.PCB中,R41--->U12的F通道还出现了断板情况.,后来通过飞线解决.不知道有没有其他暗病.走一步算一步.整个系列下来,内心还是挺烦躁的.

错板.jpg


F通道断板.jpg
飞线.jpg

修复完.jpg






喜欢研究如何让电子产品变得更加智能和有趣.
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:95
  • 最近打卡:2025-06-12 08:58:25

733

主题

1万

回帖

1万

积分

管理员

积分
16461
发表于 2023-4-26 16:55:48 | 显示全部楼层

本楼层我们随时可以下沉或删除,不影响楼主编辑创作


做为楼主发帖:
1,可以反复修改自己的各层分贴;
2,先发个N层/20层/60层,自己后面再完善修改其中的各楼层内容
3,一层也可以发表多章节
这样就可以先开放了
还有我们可以帮楼主删除部分他人跟贴/或下沉某个跟贴,帮楼主将后来楼主发表某个跟帖的,置顶到2楼


本楼层我们随时可以下沉或删除,不影响楼主编辑创作

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-27 08:54:29 | 显示全部楼层
本帖最后由 t176 于 2023-5-5 11:30 编辑

Lesson 7
数码管实践(静态和动态扫描)

段码讲解:
通过上一课的学习,我们已经能点亮指定数码管中的一个发光二极管通道
我们接下来通过仿真的方式学习下,段码和位码的原理


首先在ISP 中将试验箱设置成仿真
1.png

因为代码很简短,我们直接F8 单步调试到while 中,进行空循环
2.png


我们再观察试验箱的 现象,已经成功点亮数码管 的F通道
3.jpg

我们在仿真中,查看下内存的段码 数据
4.png


我们可以看到 P6 的数据是DF 我们将它转换成二进制 ,再和数码管的排序进行比对
5.png 6.png


眼尖的小伙伴们 应该发现规律

1   1    0   1        1   1   1   1    二进制
dp  G   F   E        D   C   B  A   对应段码

小知识点:
dp:就是小数点,有的数码管样式是: 也是dp位.

因为试验箱中使用的共阳数码管,也就是说, IO口为0情况下,通道才能点亮.

是不是 很简单,明白了 这个道理,那么我们应该如何点亮 一个数字5呢?
7.png

我们通过刚才的学习,将它转成二进制


1   0    0   1        0   0   1   0    二进制
dp  G   F   E        D   C   B  A   对应段码


8.png

10010010 B = 92 H

现在去内存中将DF,修改成92 试试.
9.png

我们看下试验箱的 现象:
10.jpg


是不是很简单.........段码讲完了.....别说你没弄明白

位码讲解:

段码我们已经学习完了,现在说说位码,刚才的实验现象可以看到,5显示在 第一位数码管上 如果我们需要让他显示在第二位数码管应该怎么做呢?
从之前的原理图中我们了解过,位控制位COM0-7
使用P7IO口 进行控制,那么我们去看下内存中的P7数据
11.png

我们将7F HEX转换成二进制 01111111,是不是很熟悉. 那么如果显然他 点亮第二位 是不是只要改成 10111 1111 再将10111 1111 B 转换成HEX 是 BF
我们也去内存中将 P7的数据改成 BF HEX
12.png

我们再观察下实验现象:
13.jpg

是不是已经达到我们的预期效果.理解了 段码后,位码  是不是感觉好简单....


根据刚才学的知识 你可以根据数码管  制造  很多奇奇怪怪的 字符 ,甚至,可以通过 流程控制 写一个 花样流水灯.

实际数码管应用中,我们比较常见的 还是数字和简单的英文.下面我给整理出来了,这样你就不需要自己一个个的去制造段码了.

试验箱中使用的共阳:

  1. unsigned char code leddata[]={
  2.                 0xC0,  //"0"
  3.                 0xF9,  //"1"
  4.                 0xA4,  //"2"
  5.                 0xB0,  //"3"
  6.                 0x99,  //"4"
  7.                 0x92,  //"5"
  8.                 0x82,  //"6"
  9.                 0xF8,  //"7"
  10.                 0x80,  //"8"
  11.                 0x90,  //"9"
  12.                 0x88,  //"A"
  13.                 0x83,  //"B"
  14.                 0xC6,  //"C"
  15.                 0xA1,  //"D"
  16.                 0x86,  //"E"
  17.                 0x8E,  //"F"
  18.                 0x89,  //"H"
  19.                 0xC7,  //"L"
  20.                 0xC8,  //"n"
  21.                 0xC1,  //"u"
  22.                 0x8C,  //"P"
  23.                 0xA3,  //"o"
  24.                 0xBF,  //"-"
  25.                 0xFF,  //熄灭
  26.                 0x92  //自定义
  27.                          };
复制代码
当然,市面还有共阴,这里为了以后你们方便我也提供下:

  1. unsigned char code leddata[]={
  2.                 0x3F,  //"0"
  3.                 0x06,  //"1"
  4.                 0x5B,  //"2"
  5.                 0x4F,  //"3"
  6.                 0x66,  //"4"
  7.                 0x6D,  //"5"
  8.                 0x7D,  //"6"
  9.                 0x07,  //"7"
  10.                 0x7F,  //"8"
  11.                 0x6F,  //"9"
  12.                 0x77,  //"A"
  13.                 0x7C,  //"B"
  14.                 0x39,  //"C"
  15.                 0x5E,  //"D"
  16.                 0x79,  //"E"
  17.                 0x71,  //"F"
  18.                 0x76,  //"H"
  19.                 0x38,  //"L"
  20.                 0x37,  //"n"
  21.                 0x3E,  //"u"
  22.                 0x73,  //"P"
  23.                 0x5C,  //"o"
  24.                 0x40,  //"-"
  25.                 0x00,  //熄灭
  26.                 0x6D  //自定义
  27.                          };
复制代码


接下来是 位码表:

  1.     unsigned char code WEI_data[] = {
  2.         0x7f, // 0111 1111        b 0
  3.         0xbf, // 1011 1111        b 1
  4.         0xdf, // 1101 1111        b 2
  5.         0xef, // 1110 1111        b 3
  6.         0xf7, // 1111 0111        b 4
  7.         0xfb, // 1111 1011        b 5
  8.         0xfd, // 1111 1101        b 6
  9.         0xfe, // 1111 1110        b 7
  10.     } ;
复制代码


静态扫描:
好了段码表和位码表 都提供了.现在,可以写一个小程序巩固下:
  1. #include <STC32G.H>
  2. unsigned char code WEI_data[] = {
  3.     0x7f, // 0111 1111        b 0
  4.     0xbf, // 1011 1111        b 1
  5.     0xdf, // 1101 1111        b 2
  6.     0xef, // 1110 1111        b 3
  7.     0xf7, // 1111 0111        b 4
  8.     0xfb, // 1111 1011        b 5
  9.     0xfd, // 1111 1101        b 6
  10.     0xfe, // 1111 1110        b 7
  11. };
  12. unsigned char code leddata[] = {
  13.     0xC0, //"0"
  14.     0xF9, //"1"
  15.     0xA4, //"2"
  16.     0xB0, //"3"
  17.     0x99, //"4"
  18.     0x92, //"5"
  19.     0x82, //"6"
  20.     0xF8, //"7"
  21.     0x80, //"8"
  22.     0x90, //"9"
  23.     0x88, //"A"
  24.     0x83, //"B"
  25.     0xC6, //"C"
  26.     0xA1, //"D"
  27.     0x86, //"E"
  28.     0x8E, //"F"
  29.     0x89, //"H"
  30.     0xC7, //"L"
  31.     0xC8, //"n"
  32.     0xC1, //"u"
  33.     0x8C, //"P"
  34.     0xA3, //"o"
  35.     0xBF, //"-"
  36.     0xFF, // 熄灭
  37.     0x92  // 自定义
  38. };
  39. void Delay500ms() //@11.0592MHz
  40. {
  41.     unsigned long i;
  42.     _nop_();
  43.     _nop_();
  44.     i = 1382398UL;
  45.     while (i)
  46.         i--;
  47. }
  48. void main()
  49. {
  50.     int DUAN = 0, WEI = 0, i = 0;
  51.     WTST =0X00;
  52.     P6M0 = 0x00;
  53.     P6M1 = 0x00;
  54.     P7M0 = 0x00;
  55.     P7M1 = 0x00;
  56.     while (1)
  57.     {
  58.         for (i = 0; i < 8; i++)
  59.         {
  60.             P7 = WEI_data[i];
  61.             P6 = leddata[i];
  62.             Delay500ms();
  63.         }
  64.     }
  65. }
复制代码

试验箱现象:








通过上面的实验,我们发现只能显示一位数码管或者几位相同的数字数码管,那么有什么办法同时显示多位并且不同的数值呢呢?,这就引出 我们下面这一部分的内容:

动态扫描:
动态扫描是一种常见的多路复用显示方法,基本原理是将要显示的数字分别输出到每个数码管上,由于人眼的视觉暂留效应,数码管快速切换时会产生“看起来同时显示”的效果。
当系统的刷新率高于人眼视觉的响应速度,人眼就无法察觉到数码管的闪烁,而是错觉它们在同时显示。

在动态扫描中,每次只有一个数码管被选通,其他数码管都处于关闭状态。
所以当数码管每次切换的速度足够快,就能达到动态扫描的目的

其原理 也非常的简单.我们传入一个值只要将每一位上的数据存到一个数组中,然后用极短的时间去切换显示每一位数码管.下面是实现代码

  1. #include <STC32G.H>
  2. unsigned char code WEI_data[] = {
  3.     0x7f, // 0111 1111        b 0
  4.     0xbf, // 1011 1111        b 1
  5.     0xdf, // 1101 1111        b 2
  6.     0xef, // 1110 1111        b 3
  7.     0xf7, // 1111 0111        b 4
  8.     0xfb, // 1111 1011        b 5
  9.     0xfd, // 1111 1101        b 6
  10.     0xfe, // 1111 1110        b 7
  11. };
  12. unsigned char code leddata[] = {
  13.     0xC0, //"0"
  14.     0xF9, //"1"
  15.     0xA4, //"2"
  16.     0xB0, //"3"
  17.     0x99, //"4"
  18.     0x92, //"5"
  19.     0x82, //"6"
  20.     0xF8, //"7"
  21.     0x80, //"8"
  22.     0x90, //"9"
  23.     0x88, //"A"
  24.     0x83, //"B"
  25.     0xC6, //"C"
  26.     0xA1, //"D"
  27.     0x86, //"E"
  28.     0x8E, //"F"
  29.     0x89, //"H"
  30.     0xC7, //"L"
  31.     0xC8, //"n"
  32.     0xC1, //"u"
  33.     0x8C, //"P"
  34.     0xA3, //"o"
  35.     0xBF, //"-"
  36.     0xFF, // 熄灭
  37.     0x92  // 自定义
  38. };
  39. /*
  40. *----------------------------------------------------------------------------------------------
  41. * 函数名称:void Delay2ms()
  42. * 函数功能:延迟2ms
  43. * 入口参数:@
  44. * 函数返回:@
  45. * 当前版本: Ver1.0
  46. * 修改时间:2023/05/05 10:45:07
  47. * 作者:t176#qq.com
  48. * 创建时间:2023/05/05 10:45:07
  49. -----------------------------------------------------------------------------------------------
  50. */
  51. void Delay2ms() //@11.0592MHz
  52. {
  53.     unsigned long i;
  54.     _nop_();
  55.     i = 5528UL;
  56.     while (i)
  57.         i--;
  58. }
  59. /*
  60. *----------------------------------------------------------------------------------------------
  61. * 函数名称:void Display( long val)
  62. * 函数功能:拆分一个长整型,数码管每一位显示相关数据
  63. * 入口参数:@
  64. * 函数返回:@
  65. * 当前版本: Ver1.0
  66. * 修改时间:2023/05/05 10:43:11
  67. * 作者:t176#qq.com
  68. * 创建时间:2023/05/05 10:43:11
  69. -----------------------------------------------------------------------------------------------
  70. */
  71. void Display(long val)
  72. {
  73.     int val_arr[8]; // 定义一个大小为8的整型数组
  74.     int i, j = 0;
  75.     while (val != 0)
  76.     {
  77.         val_arr[j] = val % 10; // 取num的最后一位,存入数组
  78.         val /= 10;             // 缩小10倍
  79.         j++;                   // 移动数组下标
  80.     }
  81.     for (i = 0; i < j; i++)
  82.     {
  83.         P6 = 0XFF;                // 清除鬼影
  84.         P7 = WEI_data[j - i - 1]; // 位选择(j-i-1)反转显示
  85.         P6 = leddata[val_arr[i]]; // 段选择
  86.         Delay2ms();
  87.     }
  88. }
  89. void main()
  90. {
  91.     WTST = 0X00; // 速度最快
  92.     P6M0 = 0x00;
  93.     P6M1 = 0x00;
  94.     P7M0 = 0x00;
  95.     P7M1 = 0x00;
  96.     while (1)
  97.     {
  98.         Display(1254680);
  99.     }
  100. }
复制代码


试验箱现象:





喜欢研究如何让电子产品变得更加智能和有趣.
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-27 08:55:09 | 显示全部楼层
Lesson 8
独立键盘和矩阵键盘
喜欢研究如何让电子产品变得更加智能和有趣.
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:551
  • 最近打卡:2025-06-12 07:18:02

11

主题

70

回帖

4206

积分

论坛元老

单片机编程魔法师

积分
4206
发表于 2023-4-27 08:55:53 | 显示全部楼层
Lesson 9
点阵屏的使用
喜欢研究如何让电子产品变得更加智能和有趣.
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-6-12 18:18 , Processed in 0.196811 second(s), 100 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表