找回密码
 立即注册
查看: 3604|回复: 25

32G12K128学习打卡记录 加油GOGOGO!

[复制链接]
  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-12 22:38:01 | 显示全部楼层 |阅读模式
2024.9.12
正式开始学习STC32的内容。
回想以前写程序的时候都是按部就班的直接用别人的库函数,没有了解单片机里面真正重要的东西,拿到学校的教材也是有点晦涩难懂,相信通过接下来的学习,我可以深入的参悟这些知识。
目标:了解冲哥视频中每一行代码的原理,深化对单片机的认识与应用。
开整!

第一
冲哥的视频解答了我很多的疑惑,也给了我一个学习STC32的动力

第二集

红外发射二极管/红外接收管:发送和接受信号

电压比较电位器(滑动变阻器):与基准电压源比较,执行不同指令。

数码管:由许多可独立亮灭的发光二极管组成,显示不同的数字。

LED灯:发光

万能板:如果板子上缺少想要用的元器件可以自己焊上!(洞洞板和核心板结合的想法真是太棒了)

NTC测温:几个小贴片用于测温。检测连续的电压信号,ADC采集速度够快,采集的就越来越平缓。

18B20:温度传感器。采集精度越高速度越慢,如果温度变化过快,会采集到变化较大的离散点。

ADC按键:通过一个单片机引脚读取16个按键。(采集模拟电压来判断按下了那个按键,0-5V对应了连续的0-4095,但是要确定当前的基准电压是多少。

微信截图_20240912212513.png

24C02:保存温度传感器和基准电压的一些数值,为了保护用户参数,防止单片机突然的损坏,将这些数据存储在外部存储器里面。

矩阵按键:减少引脚的使用。在密码锁保险箱应用较多。

独立按键:每个按键都有一个引脚对应。(炸弹!)

LCD接口:一个小显示屏,可以显示字符汉字等。

LED:在对应板子上确认是否亮起。

232接口:可连接电脑,但是有点老了。

FLASH扩展:也是存储芯片,但是比24C02存储空间更大,存储一些较大的文件。

测试接口:实现下载和调试的功能。

蜂鸣电路:发出声音。


PWM模拟DAC:数字信号转模拟信号(可以生成一个波形),哈哈今天刚刚学到模拟信号转数字信号,在这里简述一下就当做是复习了

    对于一个单位脉冲信号δ(t),其函数有定义:

                                           1、在ε时间内激发矩形脉冲
δ(t)(或三角脉冲,双边指数脉冲,钟形脉冲)所包含的面积为1.

                                                                                                          微信截图_20240912220146.png

                                           2、当ε无限趋近于0时,δ(t)的极限就叫做单位脉冲函数
                                                                                                          微信截图_20240912220434.png
                                                                                                                   图1                 图2

                                           我们从极限的角度(图2)看这个函数,可以知道它的表达式为:
                                                                                                                         截图202409122209337777.jpg

                                                                    而从面积的角度(图1)来看,矩形的"宽"随着ε减小而减小,其"高"随着ε减小而迅速增大,不过在这过程中,它的面积总是不变的为1. 故也有以下的表达式:

                                                                                                                        截图202409122216053863.jpg

                                                                   根据上述描述,为什么可以知道δ(t)仅在 t=0 处,有其面积为1,所以我们引入一个信号X(t),当X(t)δ(t)相乘时,由于δ(t)的特性,信号X(t)就只剩下了 t=0时的数值,也就是取到了X(t)信号的一个点。


                                                                                                    截图202409122230085383.jpg

                                          那么怎么取到t为不同值时的信号X(t)呢? 欸☝🤗,只要给δ(t)不同的初相位就行了。这也是单位脉冲函数的乘积性质。

                                                                                                 截图202409122230367979.jpg

搜索了一下,单片机内部的数字信号处理是用ADC,经过采样量化编码等等步骤后可以得到数字信号,但是它的实现原理给我看的一愣一愣的,还得练呀。

第三集

1.STC-ISP软件的下载附说明书和软件。

STC-ISP.rar (18.2 MB, 下载次数: 130)

2.跟着手册搭建C251开发环境

c251编译环境搭建.pdf (671.7 KB, 下载次数: 180)

3.程序包的下载

http://www.stcmcudata.com/STC8F-DATASHEET/STC32G-DEMO-CODE.ZIP


4.第一个工程的编译


添加头文件以及程序测试
截图202409131255322846.jpg

5.购买的屠龙刀还在路上,现在只能无实物学习了,期待一手

程序下载:将板子通过USB线链接电脑按下P3.2按钮,此时按下并松开OFF按钮,在松开P3.2进入USB下载模式

截图202409131303128581.jpg


stc32G试验箱说明书.pdf (5.08 MB, 下载次数: 189)


6.看了一眼跑马灯程序,发现是老师上课用的案例,简单回顾一下。


    三个头文件,包含了寄存器位置还有很多的定义。
       截图202409131309113924.jpg


    typedef,给数据类型起一个新名字。
       截图202409131310084473.jpg


    延时函数delay_ms 延时n毫秒
    #define MAIN_Fosc  24000000UL晶振频率
    6000为经验值,使得i = MAIN_Fosc / 6000 = 4000 ,即这一个循环里面i就循环了4000次,大致为1ms的时间。

       截图202409131311215349.jpg

       P6^0在STC32G.h中被定义为P60,而且P口是可位寻址的寄存器(地址为0或8的倍数),所以可以直接对一个位进行操作。

       截图202409131617042294.jpg

    这一部分寄存器的内容完全不懂,希望后面可以有学到


       截图202409131623302664.jpg

1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-13 17:28:45 | 显示全部楼层
本帖最后由 惦饭宝 于 2024-9-17 09:48 编辑

第四集:1.点亮第一颗LED灯😁

概念引入:输出电压=VCC就是高电平,输出电压=GND(一般是0V)就是低电平,分别用1和0来表示这个是理想值。

单片机引脚P口-I/O口:
GPIO(general purpose intput output)是通用输入输出端口的简称,可以通过软件来读取其输入电平,或者控制他输出高低电平。
P0是一组GPIO口,P0.0是一组中的一个GPIO口,因为P0是可位寻址的寄存器。

👇P4.0口输出低电平,使得Q11SS8550三极管导通,三极管导通后让P6口对应位输出低电平0,使发光二极管导通


截图202409141008007122.jpg
原理图下载:

stc32g实验箱原理图.pdf (374.9 KB, 下载次数: 176)

新建工程
1.选择对应的芯片:

截图202409141014174769.jpg

2.新建一个.c文件并放置到Source Group1中(直接点ADD New Item....也行)

截图202409141018429774.jpg

3.键入代码

截图202409141023331025.jpg

4.将Create HEX_File打勾,这样可以自动生成下载文件

截图202409141025316188.jpg

5.由于没有头文件,所以查看STC32G手册手动写入P口的地址

截图202409141032035286.jpg
截图202409141032321942.jpg

定义端口👇

截图202409141033154422.jpg


学习总结:
C语言代码的定义方法:

截图202409141035553084.jpg

遇到括号代码需要缩进4格

注释要完整!

//单行注释

/*
  多行注释
*/


第四集:2.实现自动下载工程😁

问题:每次下载程序之前都需要按下按钮,略显麻烦。

解决方法:见手册5.15用户程序复位到系统区进行 USB 模式 ISP 下载的方法。
Ps:要注意名称的大小写,会报未定义的错误。

截图202409131638172783.jpg

截图202409131637496781.jpg

截图202409131639348389.jpg

stc_usb_hid_32.lib文件下载

stc_usb_hid_32.LIB (81.29 KB, 下载次数: 170)

另外还需要添加一个初始化函数和一个sys_init();在主函数main

截图202409131653179835.jpg


stc_usb_cdc_32.lib也可以实现直接下载程序的功能,但是要添加以下代码

stc_usb_cdc_32.LIB (84.39 KB, 下载次数: 159)

截图202409131710141359.jpg

PS: 截图202409131714201737.jpg
并且在STC-ISP中勾选这个按钮:

截图202409131711585497.jpg

成功后会弹出CDC的串口👇

截图202409131712458864.jpg

课程总结

头文件
头文件中定义了许多SFR(特殊寄存器),也可以删除一些不需要的寄存器定义。

函数定义:
自定义的函数可以放在前面或者后面,但是因为编译器是从头开始往后编译,
所以当函数放到后面了之后,需要声明函数,在前面添加void xxxxx();

代码文件可以复制,直接修改之后不会影响原来的文件

了解了新工程的建立流程

I/O口高低电平对应不同的1/0电平

sbit可以定义某个寄存器

"#include"引入头文件

//写注释是一个良好的习惯

课后作业
个人认为点亮8个灯只要把P6的所有位定义为0,即0000 0000B,
在主函数中写入
while(1){
      P6 = 0x00;
}
//成功点亮
截图202409141421461430.jpg




回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-14 14:39:39 | 显示全部楼层
本帖最后由 惦饭宝 于 2024-9-17 10:43 编辑

第五集:C语言运算符和进制数的入门😎

1.C语言Printf函数的实现

  先添加主程序:

        if(DeviceState != DEVSTATE_CONFIGURED)  //等待USB完成配置 判断USB是否连接成功
            continue;
               
        if (bUsbOutReady)      //判断是否接收到数据
        {
            printf("xxxxx");
            usb_OUT_done();    //接受应答(固定模式)
         }
  Ps:注意大小写,不然容易报错

  标志格式:

截图202409142011165577.jpg

  输出格式字符:
截图202409142015217255.jpg

  转义字符:
截图202409142016423309.jpg

  ASCLL码表:
截图202409142025062077.jpg

各种进制之间的转换:
那么进制怎么计算才能转换成另一种进制。让我们先考虑十进制转换成 N 进制,以及 N 进制转换成十进制(N 可以为任意进制,比如 2、8 或者 16)。
十进制值转换成 N 进制
  • 假设十进制值为 D1
  • D1 对 N 取余,得到的余数作为 N 进制第一位(低位)的值
  • D1 除以 N,将结果取整,作为下一轮计算的十进制值,记该值为 D2
  • D2 对 N 取余,得到的余数作为 N 进制第二位的值
  • D2 除以 N,将结果取整,作为下一轮计算的十进制值,记该值为 D3
  • 循环执行上面的逻辑,直到 Dx 除以 N 取整后的值为 0
例如,使用上面的公式将十进制值 19 转换成二进制,步骤是
  • 19 % 2 = 1,将 1 作为二进制值的最低位;19 / 2 = 9.5,取整数 9
  • 9 % 2 = 1,将 1 作为第二位;9 / 2 = 4.5,取整数 4
  • 4 % 2 = 0,将 0 作为第三位;4 / 2 = 2
  • 2 % 2 = 0,将 0 作为第四位;2 / 2 = 1
  • 1 % 2 = 1,将 1 作为第五位;1 / = 0.5,取整数 0,流程结束
  • 最终的二进制值为 10011
N 进制值转换成十进制
  • 假设二进制值为 B1
  • 从低位开始,将 B1 每一位的值,乘以 N 的(位数 - 1)次方
  • 将步骤 2 的每个乘积相加,即得到十进制值
例如,要将二进制值 1101 转换成十进制,步骤是
  • 1101 一共有 4 位,从低位开始,第一位是 1,第二位是 0,第三位是 1,第四位是 1
  • 第一位的计算结果是 1 * 2 ^ (1 - 1) = 1 * 2 ^ 0 = 1 * 1 = 1,其中 2 ^ 0 表示 2 的 0 次方
  • 第二位的计算结果是 0 * 2 ^ (2 - 1) = 0
  • 第三位的计算结果是 1 * 2 ^ (3 - 1) = 4
  • 第四位的计算结果是 1 * 2 ^ (4 - 1) = 8
  • 十进制的转换结果是 1 + 0 + 4 + 8 = 13
  • 其他进制的相互转换,可以用上面的方法,先将它转成十进制,再转成目标进制

大一学的C语言以一种奇怪的方式在我脑袋里面复活了🙃


第五集:2.C语言运算符和进制数的入门😊

C语言常用运算符
算术运算符:+ (加) , - (减) ,* (乘) ,/ (除) ,%(取余,模运算) ,++ (自增) ,–(自减)

关系运算符:>(大于) ,<(小于) ,==(等于) ,!=(不等于) ,>=(大于等于) ,<=(小于等于)

逻辑运算:&& (与) ,|| (或) ,! (非)

赋值运算符
  = (赋值)
  += ,-= ,*=, /= ,%= (算术复合赋值运算符)
  &=, |=,^=,~,>>,<<(位运算复合赋值运算符)

位运算符:&,|,^,~,>>,<<

条件运算符:?:(条件运算符,三目运算符,三元运算符)

逗号运算符:,(逗号运算符)

指针运算符:&(取地址符) *(寻址符)

求字节运算符:sizeof(获取字节数)

特殊运算符:()(括号运算符,更改表达式运算顺序),[ ](数组下指针访问成员运算符),·(结构体变量访问成员运算符)、

C语言常用数据类型

截图202409142040599285.jpg


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-15 09:00:22 | 显示全部楼层
本帖最后由 惦饭宝 于 2024-9-15 09:02 编辑

第六集:LED闪烁和花式点灯😋


1.基于Delay实现的LED闪烁

1s = 1000ms = 1000 000μs
先键入以下代码:

    #define MAIN_Fosc        24000000UL

    void  delay_ms(u8 ms)
    {
         u16 i;
         do{
              i = MAIN_Fosc / 6000;
              while(--i);
         }while(--ms);
    }

    三个头文件,包含了寄存器位置还有很多的定义。

      


    typedef,给数据类型起一个新名字。


      

    延时函数delay_ms 延时n毫秒
    #define MAIN_Fosc  24000000UL 晶振频率//定义了一个主时钟
    6000为经验值,使得i = MAIN_Fosc / 6000 = 4000 ,即这一个循环里面i就循环了4000次,大致为1ms的时间。

      

    延时函数的缺陷:在delay的过程中无法执行别的步骤

    While(1){...}死循环,一直在这个循环中运行
    do...while,无论是条件①是否成立,代码②一直会先执行一次
    while,他会在代码执行前先判断①条件是否成立,如果成立才会执行②代码

2.函数的使用

    在模块化编程里,函数使用分为如下三步:
    1.函数定义
    返回值·函数名称( 入口参数 )
        {
            函数要执行的功能
        }
    @返回值:没有返回值就是void
    @函数名称:避开关键词,不重复,非特殊字符随便取
    @入口参数:类型+名称,多个参数“,”分开,空就写void2.
    2.函数声明
        返回值 函数名称( 入口参数 );3.函数调用
    3.函数名称(入口参数 );

3.模块化编程

    新建xxx.c和xxx.h文件,代表一个功能块,相当于一个头文件
    xxx.h格式:
        #ifndef___XXX_H
        #define___XXX_H
        用头文件函数声明...
        #endif
    xxx.c格式:
        #include"xxx.h"
        函数定义
    添加文件、定要记得引用路径和添加到工程里。
     
    双击Source Group1添加.c文件   

    引用路径👇
    截图202409150837496754.jpg

4.课后练习:SOS灯光编写

   








回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-15 16:00:07 | 显示全部楼层
本帖最后由 惦饭宝 于 2024-9-15 16:27 编辑

第七集:按键点灯😄
1.按键原理
    常开按键,开关按下①/②闭合导通
    截图202409151520557792.jpg   
    截图202409151522551563.jpg

2.机械开关缺陷

    因为按键是机械开关所以当机械触点断开、闭合时,由于机械触点的弹性作用,
    一个开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,所以在开关闭合及断开的瞬间会伴随一连串的抖动(电压上下波动)。
    对于一个开关来说,整个按键周期中有效的时间大约在50-200ms。
    大约10ms之后就是正常的低电平。

    截图202409151525199566.jpg

3.按键的实现代码
//------------------------------------------------基础代码---------------------------------------------------------
                 if( KEY == 0)
                 {
                      Delay_ms(10);
                      if( KEY == 0)
                      {  
                         执行功能;
                       }
                  }

//------------------------------------------------按下点亮,松开熄灭------------------------------------------------        
                if( KEY1 == 0  )        //判断按键有没有按下
                {
                        delay_ms(10);
                        if( KEY1 == 0 )
                        {
                                printf("按键P32已经按下\r\n");
                                P60 = 0;        //LED0点亮
                        }
                }
                else                //如果没有按下
                {
                        P60 = 1;        //LED0点亮
                }
//------------------------------------------------按下熄灭,松开点亮------------------------------------------------                
                if( KEY2 == 0  )        //判断按键有没有按下
                {
                        delay_ms(10);
                        if( KEY2 == 0 )
                        {
                                printf("按键P33已经按下\r\n");
                                P67 = 1;        //LED熄灭
                        }
                }
                else
                {
                        P67 = 0;        //LED熄灭
                }               
//------------------------------------------------按下一次,状态取反------------------------------------------------               
                if( KEY2 == 0  )        //判断按键有无按下
                {
                        delay_ms(10);
                        if( KEY2 == 0 )                //按键按下
                        {
                                while(KEY2 == 0)                //如果按键时一直按下的,那就执行while
                                {
                                }
                                printf("如果P33已经按下,led取反一次\r\n");
                                P67 = !P67;        //LED熄灭                        
                        }
                }       
//------------------------------------------------按下一次,灯往左边移动一位-----------------------------------------------                
                if( KEY2 == 0  )        //判断按键有没有按下
                {
                        delay_ms(10);// 消抖,等待10毫秒
                        if( KEY2 == 0 )// 再次判断按键是否仍然被按下,确保按键按下有效
                        {
                                printf("P33已经按下,led往左移动一位\r\n");

                               // 打印消息到串口,表示按键已被按下,LED将往左移动一位
                                LED_Data = ( (LED_Data<<1) +1 );                //先计算后输出P6
                                                   // LED_Data左移一位,使得LED显示往左移动

                                                   // 然后在最低位加1,点亮最右边的LED灯                                
                                if( LED_Data == 0XFF )// 检查LED_Data是否等于0xFF,即所有LED灯都被点亮
                                        LED_Data = 0xFE; // 如果是,重置LED_Data为0xFE,只保留最高位点亮
                                
                                P6 = LED_Data; // 将LED_Data的值输出到P6端口,更新LED的状态
                                while(KEY2 == 0); // 等待按键松开
                                                  // 如果按键一直按下,程序会一直停在这个循环中,防止多次触发按键事件            
                        }

                }
//------------------------------------------------按下一次,灯往右边移动一位-----------------------------------------------
                if( KEY2 == 0  )        //判断按键有没有按下
                {
                        delay_ms(10);// 消抖,等待10毫秒
                        if( KEY2 == 0 )// 再次判断按键是否仍然被按下,确保按键按下有效
                        {
                                printf("P33已经按下,led往右移动一位\r\n");

                               // 打印消息到串口,表示按键已被按下,LED将往左移动一位
                                LED_Data = ((
LED_Data >> 1)|0x80);                //先计算后输出P6
                                                   // LED_Data右移一位,使得LED显示往右移动

                                                   // 然后在最高位加1,点亮最左边的LED灯                                
                                if( LED_Data == 0XFF )// 检查LED_Data是否等于0xFF,即所有LED灯都被点亮
                                        LED_Data = 0x7F; // 如果是,重置LED_Data为0x7F,只保留最高位点亮

                                
                                P6 = LED_Data; // 将LED_Data的值输出到P6端口,更新LED的状态
                                while(KEY2 == 0); // 等待按键松开
                                                  // 如果按键一直按下,程序会一直停在这个循环中,防止多次触发按键事件            
                        }
                }
//-----------------------------------------------------------------------------------------------------------------------------

4.数组的使用
        
    数组使用分为如下两步
        1.定义
    类型:名称[长度]={数值};
        2.使用
    赋值:名称[索引]=数值;


    截图202409151624159148.jpg





回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-15 18:35:47 | 显示全部楼层
本帖最后由 惦饭宝 于 2024-9-16 17:19 编辑

第八集:蜂鸣器的应用😀

1.认识蜂鸣器
    1)有源蜂鸣器内部带震荡源,所以只要一通电就会叫而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。
    2)价格不同,有源蜂鸣器要比无源蜂鸣器贵,贵在里面多子震荡源
    3)播放音乐上,无源蜂鸣器效果更好
    截图202409161616532027.jpg
2.控制原理
    P54作为开关,低电平导通T2-SS8550三极管,高电平断开。
       截图202409161618072092.jpg

3.蜂鸣器实战应用
    课堂内容:1、按键1按下,蜂鸣10msLED1-8全部点亮200ms在熄灭,表示开机。
                        if( Run_Flag==0 )                        //还没有开机
                        {
                            Run_Flag = 1;                        //开机变量改为1,表示已经开机了
                            BEEP = 0;                                //打开蜂鸣
                            delay_ms(10);                        //延时10ms
                            BEEP = 1;                                //关闭蜂鸣
                            P40 = 0;                                //打开led的总电源
                            P6 = 0X00;                                //点亮全部LED
                            delay_ms(200);                        //延时200ms
                            P6 = 0XFF;                                //熄灭全部LED
                        }

             2、开机后,按键2按下,蜂鸣10ms,LED1-8轮流点亮,表示切换煲汤、烧水等功能。
                        if( KEY2 == 0 )
                        {
                            delay_ms( 10 );
                            if( KEY2 == 0 )
                            {
                                while( KEY2 == 0);                //等待松开执行了
                                BEEP = 0;                        //打开蜂鸣
                                delay_ms(10);                        //延时10ms
                                BEEP = 1;                        //关闭蜂鸣                        
                                Run_Mode ++;                        //模式选择
                                if( Run_Mode>8 )                //如果模式>8
                                Run_Mode = 1;                        //回到模式1


                                //P6 =        0XFE;   P6<<1+1
                                       
                                P6 = ~(1<< (Run_Mode-1));        //1<<1  0000 0001 -> 1111 1110                          
                            }
                        }

             3、开机后按键1再次按下,蜂鸣10ms,LED全部熄灭:表示关机
                        else                                    //已经开机
                        {
                            Run_Flag = 0;
                            BEEP = 0;                                //打开蜂鸣
                            delay_ms(10);                        //延时10ms
                            BEEP = 1;                                //关闭蜂鸣        
                            P6 = 0XFF;                                //熄灭全部LED        
                            Run_Mode = 0;                        //模式清0                                
                        }


4.学习心得
    今天网好差 视频一卡一卡的😤,不过也是学会了蜂鸣器、按键、LED的搭配使用方法,头文件的嵌套有点懵,其他还好。
    虽然说只需要控制一个引脚就可以让蜂鸣器工作,但是视频里面没有说怎么让蜂鸣器发出不同频率的声音,好奇捏。



文件: 蜂鸣器.zip (132.34 KB, 下载次数: 146)


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-17 08:44:03 | 显示全部楼层
本帖最后由 惦饭宝 于 2024-9-17 20:32 编辑

第九集:静态数码管☝😎
1.认识数码管
    数码管也叫LED数码管,内部是由多个发光二极管封装在一起组成,他们可以有很多种颜色,很多种外形,很多种样式,但是本质来说他们都是通过点亮内部的LED来显示的,只要面板做好了,理论可以显示任意的字符或者图案。
    按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管,尾缀A表示共阳,K表示共阴
    截图202409170825318634.jpg
    截图202409170830039294.jpg

2.控制原理
   COM0-COM7为从右到左的数码管编号,其通过控制P7来打开,P6口控制显示的是什么字符。
    截图202409170832004903.jpg

    截图202409170832347309.jpg

3,数码管应用

    使用数组保存0-9的16进制表示:
    SEG_Tab[10] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90 };//0-9
    PS:使用的是上图共阴的管子,共阳需要取反。☝😎

    尝试用延时实现0-9的循环显示。

    思路:使用简单的延时函数来控制数字的循环显示,每隔一段时间更新一次数字,从0到9,然后重复循环。
    示例:
               P6 = SEG_Tab[num];        //这个数码管输出段码
                num ++;
                if( num>9 )
                   num = 0;
               
                delay_ms(1000);


    用按键控制数字的加或者减。
    思路:设置两个按键,一个用于数字的增加,一个用于数字的减少。
          按下增加按键,数字增加1;按下减少按键,数字减少1。
          数字范围限制在0到9,超出范围时进行循环,例如:从9增加到0,从0减少到9。
    示例:
                P6 = SEG_Tab[num];            //这个数码管输出段码
                if( KEY1 ==0 )              // 检测按键KEY1是否被按下
                {
                    delay_ms(10);           // 消抖处理,等待10毫秒
                    if( KEY1 ==0 )          // 再次确认按键KEY1是否仍然被按下
                    {
                        BEEP = 0;           // 打开蜂鸣器,发出短暂的声音提示
                        delay_ms(10);       // 蜂鸣器持续时间,延时10毫秒
                        BEEP = 1;           // 关闭蜂鸣器
                        while( KEY1 ==0 ); // 等待按键释放,防止多次触发按键事件
                        if( num<9 )         // 如果当前显示的数字小于9
                            num++;          // 数字增加1
                    }
                }

                if( KEY2 ==0 )
                {
                    delay_ms(10);
                    if( KEY2 ==0 )
                    {
                        BEEP = 0;
                        delay_ms(10);
                        BEEP = 1;                                
                        while( KEY2 ==0 );
                        if( num>0 )         // 如果当前显示的数字大于0

                            num--;          // 数字减少1
                     }        
                 }

4.课后总结
    学会了数码管的原理,如何控制管脚了显示对应的字符,以及在那个数码管显示。😎
    通过数组的方式将0-9的数值用16进制储存,以后使用快捷方便。
    初步学会了数码管的一些应用以及按键的一些搭配形式。

5.课后练习

    1)尝试使用数码管显示HJLNOPUtr等字母或符号。


    截图202409170940272176.jpg
   

    文件: 数码管.xlsx (95.1 KB, 下载次数: 133) Ps:有些字母和数字串用了,比如0和O。😥我手上现在没有实验箱,无法做验证,可能有一些错误,欢迎批评指正。

    2)通过一个按键设置数码管显示数字0-9循环,在按一下另一个按键的时候,数码管上显示的数字几,蜂鸣器就响几声。



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-17 10:47:02 | 显示全部楼层
本帖最后由 惦饭宝 于 2024-9-17 20:22 编辑

第十集:动态数码管👦
1.数码管动态刷新的原理
    数码管动态刷新是一种通过快速切换数码管的显示,以实现多个数码管同时显示不同数字的方法。
    它利用人眼的视觉暂留现象,使人感觉到数码管上的数字是同时显示的。  
    截图202409171611324622.jpg
    动态刷新主要是通过分时显示的方法,将多个数码管依次点亮。每次只点亮一个数码管,而其他的数码管则保持熄灭状态。
    由于每个数码管只在短时间内被点亮,因此需要快速切换,这样人眼在视觉上就会感受到所有数码管是同时亮的。
    动态刷新需要多个控制信号来选择哪一个数码管被点亮,以及选择数码管上的哪个段位被点亮。通常需要使用多个I/O口或者串行移位寄存器来实现这些控制信号的输出。
    截图202409171612137737.jpg

    刷新频率要足够快,通常在几十到几百赫兹之间,这样才能避免人眼察觉到闪烁。

2.控制原理

    具体的控制的流程如图所示,N表示有几个数码管!
    截图202409171612535511.jpg
    其中需要注意每个延时不能太短,我们这边程序就以1ms为准,且需要保证总共一个循环结束的时间不能大于20ms,因为人眼的视觉不容易分辨出50HZ以上的动态刷新。

3.实验任务
    1)在上一课的基础上,新增一个位码选择的数组
    u8 COM_Tab[8] = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };        //0-7的位码数组

    2)通过调用数组选择位码
    截图202409171626556272.jpg

    可编辑文件: 数码管.xlsx (95.91 KB, 下载次数: 159)

    3)新建一个数组选择每个位需要显示的内容!

        u8 Show_Tab[8] = {3,0,0,0,0,10,0,0};    //让对应数码管显示输入的数字
        P6 = SEG_Tab[Show_Tab[num]];             //需要显示的数字的内码 赋给 P6   NUM =0 -> Show_Tab[num]] = 1 -> p6 = 0xF9

4.实战小练:
    简易10秒免单计数器
        👇提前定义数组,以及判断标志
        u32 TimCount = 0;                //计数单位1ms
        bit RUN_State = 0;               //开始运行/结束运行
        u8 SEG_Tab[20] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//0-9段码,0-9带小数点
        Show_Tab[0]  = 1;                //选择 1
        Show_Tab[1]  = 10;               //选择 0.
        Show_Tab[2]  = 0;                //选择 0
        Show_Tab[3]  = 0;                //选择 0
        👆前四位显示1 0. 0 0


    1.在前四位数码管上显示目标时间,即10.00”表示定时时间10秒钟

        注意点:带有小数点,需要修改对应数组
    2.后四位显示当前的计时00.00,最小单位为10ms

    3.按下开始按钮后,每10ms最末尾的数字+1;知道按下结束按钮后停止计数。
        if( RUN_State==1 )                              // 如果运行状态为1(RUN_State == 1)
        {                                               // 计时器计数加1  
            TimCount++;
            Show_Tab[4] = TimCount/10000%10;            // 获取万位数字并显示
            Show_Tab[5] = TimCount/1000%10+10;          // 获取千位数字并显示(+10用于特殊显示,小数点)
            Show_Tab[6] = TimCount/100%10;              // 获取百位数字并显示
            Show_Tab[7] = TimCount/10%10;               // 取10位
        }
        
        SEG_Fre();                                      // 更新数码管显示

        if( KEY1 ==0 )
        {
            delay_ms(10);
            if( KEY1 ==0 )
            {
            BEEP = 0;
            delay_ms(10);
            BEEP = 1;
            while( KEY1 ==0 )
                SEG_Fre();                               // 不断刷新数码管显示
            if( RUN_State==0 )                           // 如果运行状态为0
                TimCount = 0;                            // 重置计数器
                        
            RUN_State = !RUN_State;                      // 切换运行状态
            }
        }  

5.课后练习
    一、做一个简易时钟,功能如下1.初始状态显示 00-00-00,分别作为时,分,秒
    二.每隔一秒钟,秒+1,一分钟,分+1,以此类推
    三.时间到达00-00-30的时候,蜂鸣响3秒钟表示闹钟

             添加部分:
        数组数量加1,第21个为横杠。
        u8 SEG_Tab[21] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xBF};        //0-9段码,0-9带小数点,横杠-
        设置Show_Tab[8]第3位和第五位为横杠。
        u8 Show_Tab[8] = {0,0,20,0,0,20,0,0};     //Show_Tab[20]对应SEG_Tab的第21个

        新增时,分,秒计数单位。
        u16 H = 0,M = 0,S = 0;
        代码:
//----------------------------------------------------------------------------------------------------------------------------------------------------//
        delay_ms(1000);
        S++;

        // 判断闹钟
        if(RUN_State == 0 && S == 30) //第一次S=30时,蜂鸣器响3秒。
        {
            BEEP = 0;
            delay_ms(3000);
            BEEP = 1;
            RUN_State = 1;
        }
       //当S == 60时,M+1,当M == 60时,H+1
        if(S >= 60)
        {
            S = 0;
            M++;
            if(M >= 60)
            {
                M = 0;
                H++;
                if(H>24)
                {
                    H = 0;
                }
            }
        }

        //0,1,3,4,6,7为数码管需要显示部分;

        Show_Tab[6] = S /10 ; //显示秒的十位
        Show_Tab[7] = S %10 ; //显示秒的各位


        Show_Tab[3] = M /10 ; //显示分的十位
        Show_Tab[4] = M %10 ; //显示分的各位

        Show_Tab[0] = H /10 ; //显示时的十位
        Show_Tab[1] = H %10 ; //显示时的各位        

        SEG_Fre();        
//----------------------------------------------------------------------------------------------------------------------------------------------------//
PS:没有试验箱,代码还未验证,若有错误还望批评指正!

6.课后总结😁
    学习了如何在数码管上显示小数点,并通过按键控制计时的开始和停止。按键消抖以及蜂鸣器的使用也是更加熟练。
动态数码管理解:数码管动态刷新是通过快速切换数码管的显示来实现的。每次只点亮一个数码管,通过不断轮流点亮各个数码管,使人眼感受到所有数码管同时显示。
    实现过程中,刷新频率必须足够快,通常在几十到几百赫兹之间,以避免视觉上感到闪烁。
    学到了如何控制数码管的显示,包括使用位码选择数组和段码选择数组。在实现过程中,重点是通过循环不断切换显示内容,使数码管能够正确显示多个数字。
    ALL👆



   学习文件: 动态数码管.zip (203.58 KB, 下载次数: 154)



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看II
  • 打卡总天数:29
  • 最近打卡:2024-10-23 17:26:58

5

主题

19

回帖

209

积分

中级会员

积分
209
发表于 2024-9-18 09:04:03 | 显示全部楼层
本帖最后由 惦饭宝 于 2024-9-19 11:41 编辑

第十一集:定时器的使用👌
1.定时器的作用和意义
      定时器的工作原理基于定时器芯片上的计数器。当开始计时时,计数器开始递增计数。定时器通过使用时钟信号来触发计数器的递增,随着计数器不断递增,一旦计数器的值达到了预设的时间间隔,定时器将会触发预定的行为,如打开或关闭一个电路
    定时器是定时器和计数器的统称。
    1)设置为定时器时,可实现硬件计时,或者使程序每隔一固定时间完成一项操作。
    2)设置为计数器时候能够对脉冲进行计数
    3)替代长时间的delay,提高CPU的运行效率和处理速度,能及时的响应某个事件

    截图202409180859592120.jpg

2.STC32G单片机定时器使用原理

1)先设置功能为定时器/计数器
    定时器/计数器的核心部件是一个加法计数器,本质是对脉冲进行计数。

    截图202409182129312025.jpg

    截图202409182132425712.jpg

2)如果在定时器模式下,设置不分频或者12分频。如果定时时间够,那么12分频就可以
    截图202409182134553229.jpg

    截图202409182134334695.jpg

    PS:默认是12分频。

    截图202409182137356617.jpg

    截图202409182137467466.jpg

3)定时器的工作模式
    截图202409182139525811.jpg

    如果设置为16位自动重载,那么它的计数就可以计到0-65535(2^16)。8位自动重载就是0-255(2^8)
    自动重载就是每次时间到了就把计数的值自动写进去,不自动重载的话就要手动将定时时间写一遍。
    不可屏蔽重载:该中断一开启就是最高优先级,不可被任何中断打断。

    截图202409182140071097.jpg

4)定时器设置
    一旦产生中断,TF0就会硬件置1,运行前TF0可以软件清0。
    TR0必须在启动前手动写1,不然中断无法开启!

    截图202409182146018688.jpg

5)中断
    截图202409182149393801.jpg

3.定时器的简单应用
    系统时钟可以理解为IRC👇
      截图202409182152149479.jpg
    截图202409182151358722.jpg

    定时时间的计算公式:


    截图202409182153578122.jpg

   
    手册设置定时器示例:

    截图202409182155495965.jpg

    中断号:需要看手册,比如定时器0就要用interrup 1。

    void Timer0_Isr(void) interrupt 1

    定时器0配置
    void Timer0_Init(void) // 1毫秒@24.000MHz
    {
        AUXR &= 0x7F; // 定时器时钟12T模式
        TMOD &= 0xF0; // 设置定时器模式
        TL0 = 0x30;   // 设置定时初始值
        TH0 = 0xF8;   // 设置定时初始值 :TL0,TH0设定定时器多少秒溢出一次
        TF0 = 0;      // 清除TF0标志
        TR0 = 1;      // 定时器0开始计时
        ET0 = 1;      // 使能定时器0中断
    }

    定时器0中断服务函数
    void Timer0_Isr(void) interrupt 1
    {
        SEG_Fre(); // 数码管刷新的

        if( RUN_State == 1 ) // 如果开始运行
        {
            TimCount++; // 每隔1ms+1
            Show_Tab[4] = TimCount/10000%10;
            Show_Tab[5] = TimCount/1000%10+10;
            Show_Tab[6] = TimCount/100%10;
            Show_Tab[7] = TimCount/10%10;
        }
    }
4.学习总结:
    定时器中断与主循环 (while(1)) 独立运行。定时器按固定的时间间隔触发中断,主循环持续执行代码,彼此之间不阻塞
    两者通过全局变量(例如 RUN_State、TimCount)进行交互。主循环负责检测按键,改变 RUN_State;定时器中断根据 RUN_State 的状态来更新 TimCount。

    EXCLE计算频率时间: 定时器频率时间计算.xlsx (91.5 KB, 下载次数: 181)

5.课后练习:
一、第十课的课后作业做一个简易时钟,在此基础上将时钟改成定时器驱动。
二、在上述基础上是增加一个按钮,按下一次就可以让时间暂停,在按一下时间又能继续走,在按一下再暂停!

添加定时器初始化
    截图202409191137378753.jpg
添加定时器0服务函数
    截图202409191138168456.jpg

将时钟时分秒的改变放到定时器中运行,在while循环中改变对应参数的数值,从而判断定时器中的if条件。

文件: Shumaguan.zip (204.29 KB, 下载次数: 173)

ALL👆

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:249
  • 最近打卡:2025-05-09 08:22:02
已绑定手机

3

主题

26

回帖

1162

积分

金牌会员

积分
1162
发表于 2024-9-18 11:22:05 | 显示全部楼层
向大佬学习!
回复 支持 0 反对 1

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-9 11:47 , Processed in 0.139857 second(s), 106 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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