t176 发表于 2023-4-24 08:42:40

STC32G12K128 成长道路

本帖最后由 t176 于 2023-4-27 08:46 编辑

Lesson 1

开篇:
LINK1D 仿真:




1.首先,仿真线路的连接;
屠龙刀:

2.目标芯片与STC LINK1D硬件仿真器通过或SWD接口连接(P3.0,P3.1),以建立仿真通讯链路;



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




PDF下载:


请注意:如果在ISP中设置为仿真芯片,没设置端口和SWD,将仿真失败

4.编写并编译代码,生成HEX文件

5.通过STC_ISP,将生成的可烧录指令文件下载到STC LINK1D硬件仿真器中的处理器内存区域,作为仿真器内部的程序;


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



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


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




















t176 发表于 2023-4-24 08:42:41

本帖最后由 t176 于 2023-4-21 16:07 编辑

Lesson 2

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

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

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

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


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


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

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


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


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




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




当然还有其他样式,在ISP 中可以查阅观察.


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


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







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

#include <STC32G.H>

void main()
{
    EAXFR = 1;    // 使能访问 XFR
    CKCON = 0x00; // 设置外部数据总线速度为最快
    WTST = 0x00;// 设置程序代码等待参数,
    // 赋值为 0 可将 CPU 执行程序的速度设置为最快
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;

    while (1)
    {
       P25=~P25;//翻转电平
    }
   
}

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


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

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



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



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



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

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



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

我们打开内存窗口



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


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


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



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

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

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




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

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





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


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

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

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


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

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

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


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

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







t176 发表于 2023-4-24 08:42:42

本帖最后由 t176 于 2023-4-22 10:31 编辑

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


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


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


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


编写代码:

#include <STC32G.H>

sbit LED = P2 ^ 5; // 位定义,将LED 变量 定义为P2口的第5个引脚

void main()
{
    EAXFR = 1;    // 使能访问 XFR
    CKCON = 0x00; // 设置外部数据总线速度为最快
    WTST = 0x00;// 设置程序代码等待参数,
    // 赋值为 0 可将 CPU 执行程序的速度设置为最快
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;

    LED = 0; // LED控制引脚为低电平
    while (1)
    {
    }
}
代码拆解:
sbit是什么
sbit是 Keil C编译器中的一种语法.用于访问单个位(bit)。在使用sbit语法时,需要指定需要访问的位所在的寄存器和位的位置.


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

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

拓展内容:

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



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



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



然后我们去代码实现下.

#include <STC32G.H>

void main()
{
    EAXFR = 1;    // 使能访问 XFR
    CKCON = 0x00; // 设置外部数据总线速度为最快
    WTST = 0x00;// 设置程序代码等待参数,
    // 赋值为 0 可将 CPU 执行程序的速度设置为最快
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;

    P2 =0XCE;//将16进制数组赋值给P2寄存器,直接操控8个LED灯
    while (1)//这是一个空循环,阻断程序继续执行,如果不加while 根据单片机的特性,main函数 在执行完毕后
    {
    }
}


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

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

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





t176 发表于 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 已经帮你做好了 你只要选下参数点下按钮就可以生成代码 .是不是很贴心.




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


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

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



#include <STC32G.H>


void Delay500ms()                //@11.0592MHz
{
      unsigned long i;

      _nop_();
      _nop_();
      i = 1382398UL;
      while (i) i--;
}



void main()
{
    EAXFR = 1;    // 使能访问 XFR
    CKCON = 0x00; // 设置外部数据总线速度为最快
    WTST = 0x00;// 设置程序代码等待参数,// 赋值为 0 可将 CPU 执行程序的速度设置为最快
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;


    while (1)//这是一个空循环,阻断程序继续执行,如果不加while 根据单片机的特性,main函数 在执行完毕后
    {
                Delay500ms();
                P25=~P25;
    }
}

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




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






t176 发表于 2023-4-24 08:42:44

本帖最后由 t176 于 2023-4-24 08:45 编辑

Lesson 5


实现一个花式流水灯


#include <STC32G.H>

#define LIGHT_COUNT 8 // LED 数量

void Delay500ms() //@11.0592MHz
{
unsigned long i;

_nop_();
_nop_();
i = 1382398UL;
while (i)
    i--;
}

void main()
{

unsigned char pattern = {
      0x01, // 0000 0001 b
      0x02, // 0000 0010 b
      0x04, // 0000 0100 b
      0x08, // 0000 1000 b
      0x10, // 0001 0000 b
      0x20, // 0010 0000 b
      0x40, // 0100 0000 b
      0x80// 1000 0000 b

};            // LED 点亮模式
EAXFR = 1;    // 使能访问 XFR
CKCON = 0x00; // 设置外部数据总线速度为最快
WTST = 0x00;// 设置程序代码等待参数,// 赋值为 0 可将 CPU 执行程序的速度设置为最快
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;

while (1)
{
    int i;
    // 反向点亮每个 LED
    for (i = LIGHT_COUNT - 1; i >= 0; i--)
    {
      P2 = ~pattern; // 控制 LED 灯亮灭
      Delay500ms();
    }

    // 轮流两个 LED 交替点亮
    for (i = 0; i < LIGHT_COUNT - 1; i++)
    {
      P2 = ~(pattern | pattern); // 控制 LED 灯亮灭
      Delay500ms();
    }

    // 轮流两个 LED 交替点亮(2)
    for (i = 7; i >= 0; i--)
    {
      P2 = ~(pattern | pattern); // 控制 LED 灯亮灭
      Delay500ms();
    }

    // 依次点亮每个 LED
    for (i = 0; i < LIGHT_COUNT; i++)
    {
      P2 = ~pattern; // 控制 LED 灯亮灭
      Delay500ms();
    }
}
}


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

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

代码中 | 的 作用    将这两个数进行合并,
~我们之前已经学过了,这里将合并计算后的结果,进行取反.

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

好了这章就先到这里,留意下数组的写法,下一章数码管学习,我们会使用类似的写法
一定要理解掌握相关的知识点,这一章其实没多少知识点,重点是要善于思考,尝试自己去写一个炫酷的花式点灯效果.




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



t176 发表于 2023-4-24 11:10:34

本帖最后由 t176 于 2023-5-2 20:13 编辑

Lesson 6


数码管的原理

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

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





原理图:


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




图1


图2


图3




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


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



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










共阳极和共阴极:

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




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

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

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



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


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



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

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



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



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

#include <STC32G.H>

void main()
{
    P6M0 = 0x00;
    P6M1 = 0x00;
    P7M0 = 0x00;
    P7M1 = 0x00;
    P7 = 0x7F; //01111111 B
    P6 = 0xDF;//11011111 B
    while (1)
    {
      
   
    }
}实验现象:



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

static/image/hrline/1.gif

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














神农鼎 发表于 2023-4-26 16:55:48


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


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


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

t176 发表于 2023-4-27 08:54:29

本帖最后由 t176 于 2023-5-5 11:30 编辑

Lesson 7
数码管实践(静态和动态扫描)
段码讲解:
通过上一课的学习,我们已经能点亮指定数码管中的一个发光二极管通道
我们接下来通过仿真的方式学习下,段码和位码的原理


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


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



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


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



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



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

1   1    0   1      1   1   1   1    二进制
dpG   F   E      D   C   BA   对应段码

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

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

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


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


1   0    0   1      0   0   1   0    二进制
dpG   F   E      D   C   BA   对应段码




10010010 B = 92 H

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


我们看下试验箱的 现象:



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

位码讲解:

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


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


我们再观察下实验现象:


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


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

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

试验箱中使用的共阳:

unsigned char code leddata[]={

                0xC0,//"0"
                0xF9,//"1"
                0xA4,//"2"
                0xB0,//"3"
                0x99,//"4"
                0x92,//"5"
                0x82,//"6"
                0xF8,//"7"
                0x80,//"8"
                0x90,//"9"
                0x88,//"A"
                0x83,//"B"
                0xC6,//"C"
                0xA1,//"D"
                0x86,//"E"
                0x8E,//"F"
                0x89,//"H"
                0xC7,//"L"
                0xC8,//"n"
                0xC1,//"u"
                0x8C,//"P"
                0xA3,//"o"
                0xBF,//"-"
                0xFF,//熄灭
                0x92//自定义

                         };
当然,市面还有共阴,这里为了以后你们方便我也提供下:

unsigned char code leddata[]={

                0x3F,//"0"
                0x06,//"1"
                0x5B,//"2"
                0x4F,//"3"
                0x66,//"4"
                0x6D,//"5"
                0x7D,//"6"
                0x07,//"7"
                0x7F,//"8"
                0x6F,//"9"
                0x77,//"A"
                0x7C,//"B"
                0x39,//"C"
                0x5E,//"D"
                0x79,//"E"
                0x71,//"F"
                0x76,//"H"
                0x38,//"L"
                0x37,//"n"
                0x3E,//"u"
                0x73,//"P"
                0x5C,//"o"
                0x40,//"-"
                0x00,//熄灭
                0x6D//自定义

                         };


接下来是 位码表:

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

静态扫描:
好了段码表和位码表 都提供了.现在,可以写一个小程序巩固下:
#include <STC32G.H>

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

unsigned char code leddata[] = {

    0xC0, //"0"
    0xF9, //"1"
    0xA4, //"2"
    0xB0, //"3"
    0x99, //"4"
    0x92, //"5"
    0x82, //"6"
    0xF8, //"7"
    0x80, //"8"
    0x90, //"9"
    0x88, //"A"
    0x83, //"B"
    0xC6, //"C"
    0xA1, //"D"
    0x86, //"E"
    0x8E, //"F"
    0x89, //"H"
    0xC7, //"L"
    0xC8, //"n"
    0xC1, //"u"
    0x8C, //"P"
    0xA3, //"o"
    0xBF, //"-"
    0xFF, // 熄灭
    0x92// 自定义

};

void Delay500ms() //@11.0592MHz
{
    unsigned long i;

    _nop_();
    _nop_();
    i = 1382398UL;
    while (i)
      i--;
}

void main()
{

    int DUAN = 0, WEI = 0, i = 0;
    WTST =0X00;
    P6M0 = 0x00;
    P6M1 = 0x00;
    P7M0 = 0x00;
    P7M1 = 0x00;

    while (1)
    {
      for (i = 0; i < 8; i++)
      {

            P7 = WEI_data;
            P6 = leddata;
            Delay500ms();
      }
    }
}
试验箱现象:
attach://9396.mp4







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

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

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

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

#include <STC32G.H>

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

unsigned char code leddata[] = {

    0xC0, //"0"
    0xF9, //"1"
    0xA4, //"2"
    0xB0, //"3"
    0x99, //"4"
    0x92, //"5"
    0x82, //"6"
    0xF8, //"7"
    0x80, //"8"
    0x90, //"9"
    0x88, //"A"
    0x83, //"B"
    0xC6, //"C"
    0xA1, //"D"
    0x86, //"E"
    0x8E, //"F"
    0x89, //"H"
    0xC7, //"L"
    0xC8, //"n"
    0xC1, //"u"
    0x8C, //"P"
    0xA3, //"o"
    0xBF, //"-"
    0xFF, // 熄灭
    0x92// 自定义

};
/*
*----------------------------------------------------------------------------------------------
* 函数名称:void Delay2ms()
* 函数功能:延迟2ms
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/05/05 10:45:07
* 作者:t176#qq.com
* 创建时间:2023/05/05 10:45:07
-----------------------------------------------------------------------------------------------
*/
void Delay2ms() //@11.0592MHz
{
    unsigned long i;

    _nop_();
    i = 5528UL;
    while (i)
      i--;
}

/*
*----------------------------------------------------------------------------------------------
* 函数名称:void Display( long val)
* 函数功能:拆分一个长整型,数码管每一位显示相关数据
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/05/05 10:43:11
* 作者:t176#qq.com
* 创建时间:2023/05/05 10:43:11
-----------------------------------------------------------------------------------------------
*/
void Display(long val)
{
    int val_arr; // 定义一个大小为8的整型数组

    int i, j = 0;
    while (val != 0)
    {
      val_arr = val % 10; // 取num的最后一位,存入数组
      val /= 10;             // 缩小10倍
      j++;                   // 移动数组下标
    }

    for (i = 0; i < j; i++)
    {
      P6 = 0XFF;                // 清除鬼影
      P7 = WEI_data; // 位选择(j-i-1)反转显示
      P6 = leddata]; // 段选择

      Delay2ms();
    }
}
void main()
{

    WTST = 0X00; // 速度最快
    P6M0 = 0x00;
    P6M1 = 0x00;
    P7M0 = 0x00;
    P7M1 = 0x00;

    while (1)
    {
      Display(1254680);
    }
}

试验箱现象:
attach://9454.mp4




t176 发表于 2023-4-27 08:55:09

Lesson 8
独立键盘和矩阵键盘

t176 发表于 2023-4-27 08:55:53

Lesson 9
点阵屏的使用
页: [1] 2 3 4
查看完整版本: STC32G12K128 成长道路