找回密码
 立即注册
楼主: 生如夏花

STC32G12K128学习心得

[复制链接]

1

主题

16

回帖

37

积分

新手上路

积分
37
发表于 2024-1-22 15:11:57 | 显示全部楼层
第十集:数码管动态显示
同时显示多个数码管时,为何使用动态刷新的方式显示:
由于多个数码管公用同一组断码控制引脚,多个数码管显示不同数字时,会相互冲突,因此通过动态刷新的方式,利用人眼的视觉暂留特性,短时间内快速切换断码和位选实现多数码管同时显示的效果。

截图202401221510293388.jpg
截图202401221510423428.jpg
截图202401221510512240.jpg
回复 支持 反对

使用道具 举报 送花

1

主题

16

回帖

37

积分

新手上路

积分
37
发表于 2024-1-22 15:15:56 | 显示全部楼层
第十一集:定时器的使用


1.定时器的作用和意义
什么是定时器:定时器-与非网
上节课的一段代码:

while(1)

{
    TimeCount++;
    delay_ms(1);
}

TimeCount++然后一个延时1毫秒,每运行1ms,变量就会加一。
系统已经运行了多少个毫秒。
实际使用时的代码如下,

while(1)
{
    TimeCount++;
    delay_ms(1);
    if (KEY1 == 0)
                {
                        delay_ms(10);
                        if (KEY1 == 0)
                        {
                                while(KEY1 == 0);
            }
        }
}

判断按键有沿有按下的时候,我们等待按键松开,还有一个while循环。
如果没有松开,会一直死在这一行。所以,按下的时间段内,TimeCount++没有在执行,变量不会动。
那么像这样while函数在不断循环执行的时候,能不能有办法让这个变量每隔1ms能自动加一,并且不受while循环的影响呢?
引入:中断的概念
如果中断不发生,就会一直执行主程序(主函数)。但是,如果中断发生了,先会进行这个中断的处理函数
处理完后,从中断返回,再继续执行主程序(之前没有完成的一个人任务)。

定时一定时间之后产生的中断,也就是定时器中断。
主程序:你在背书
中断:妈妈让你五分钟以后看一下锅里的汤有没有烧干,一个定时器中断的一个例子。

定时器是定时器和计数器的统称。
1)设置为定时器时,可实现硬件计时,或者使程序每隔一固定时间完成一项操作;
2)设置为计数器时候能够对脉冲进行计数;
3)替代长时间的delay,提高CPU的运行效率和处理速度,能及时的响应某个事件。
1、软件定时的缺点:占用CPU时间,影响CPU的运行效率和处理速断,有时会造成很大的定时误差。
2、中断的概念:中断请求、中断响应(中断处理程序)、中断返回,本节主要是讲定时器中断。
3、定时器的使用(以T0为例)
      1)设置为定时器/计数器
           寄存器TMOD的T0_CT位:0为定时模式,1为计数模式
      2)设置不分频或12分频
           通过设置辅助寄存器AUXR的T0x12:0为12分频(默认为0),1为不分频。
      3)定时器工作模式T0_M1/T0_M0
           16位自动重载模式比较常用。


      4)定时器设置 (定时器 0/1 控制寄存器TCON)
           TF0:T0 溢出中断标志。该位软件清0,也可以不清0。
          TR0:定时器 T0 的运行控制位。该位软件置1,开启定时器。
      5)中断
           IE:中断使能寄存器,EA:总中断允许控制位。EA=1允许中断。
            ET0:定时 / 计数器 T0 的溢出中断允许位。ET0=1允许定时器中断。
4、实现T0定时器中断的主要程序
       T0初始化程序
       TMOD =0x00;                // 设置定时器 0 位 16 位自动重载模式
       TL0=0x30;                     // 计算出的 24M 时钟下的 1ms 的定时时间初始值
       TH0=0xF8:
       TR0=1;                          //启动定时器
        ET0 =1;                        // 使能定时器中断
        EA = 1;                        //CPU 开放中断,打开总中

        T0中断响应程序
         void Tim0_Isr() interrupt 1 //1-定时器0中断号
         {
          }





回复 支持 反对

使用道具 举报 送花

1

主题

16

回帖

37

积分

新手上路

积分
37
发表于 2024-1-22 15:17:13 | 显示全部楼层
第十二集:

直流有刷的电机,后面两个一正一负的电接上,电机就可以转


到底是转子个几个圈呢?
我们就可以在背后加装这么一个码盘,我们假设这里是有60个这个光电的一个孔对吧
那我们转一圈是不是就可以一个轴上输出60个这样的脉冲,有遮挡就输出1,无遮挡输出0,
两路交替,如果说这圈有60个脉冲,60个高低电平(总共几个脉冲除60就是转的圈数)
本节利用开关,模拟计数器的功能。
编码器也可以实现脉冲输出,输出波形:方波
流过了多少液体,中间有个比例变化。一高一低算一个脉冲。
只要输出信号带这种高低电平变化的,想要计算个数的就可以用计数器的功能



1、计数器的用途   
只要输出信号带高低电平变化,想要计算个数的就可以用计数器的功能。

2、计数器的配置
T1_C/T:控制定时器1用作定时器或计数器。T1_C/T=1为计数器
T1_GATE:控制定时器 1,置 1 时只有在 INT1 脚为高及 TR1 控制位置 1 时才可打开定时器 / 计数器 1。此例将T1_GATE清零。

3、计数器的使用


定时器1计数器初始化代码:
TMOD=0x40;      // 设置计数器模式
TL1=0xFF;          // 设置计数初始值
TH1=0xFF;         // 设置计数初始值
TF1=0;               // 清除 TF1 标志
TR1=1;              // 定时器 1 开始计时
ET1=1;              // 使能定时器 1 中断
P3PU=0x20;      //打开内部4.1k上拉电阻
定时器1中断响应函数
   void Tim1_Isr() interrupt 3 //3-定时器1中断号
    {
    }

4、计数器应用实例
void Timer0_Isr(void) interrupt 1
{
      TinCount++;                // 每隔 1ms+1,计数到 2000=2s
      if(TimCount>=2000) //2 秒定时时间到了
     {
              TinCount = 0;
              Count_T1=(TH1 *256)+ TL1;   //读取计数器的值,
              TH1=0;
              TL1=0;
              Show_Tab[4]= Count T1/1000%10;
              Show_Tab[5]=Count_T1/100%10;
              Show_Tab[6]=Count_T1/10%10;
              Show_Tab[7]=Count_T1/1%10:// 取 10 位
              SEG_Fre();      // 数码管刷新的
        }
}


回复 支持 反对

使用道具 举报 送花

1

主题

16

回帖

37

积分

新手上路

积分
37
发表于 2024-1-22 15:21:29 | 显示全部楼层
本帖最后由 生如夏花 于 2024-1-22 15:28 编辑

十三集:模块化编程
模块化编程是将一整块代码分成不同的文件,便于调用,同时也会使得主程序内容变少,不会占用太多cpu。同时尽量养成代码注释好习惯。
在之前编程的使用:


一、LED & 数码管 --led_seg.c, led_seg.h
二、按键 --key.c, key.h
三、蜂鸣器 --beep.c, beep.h
四、定时器 --tim.c, tim.h
一个功能对应一个.c和.h
1、模块化编程:
----------------------------------------------
创建程序文件三步
    新建文件并保存
    添加到工程 (添加.c文件)
    添加引用路径


一般可以建立hardware、object、system、user四个文件夹,分别放置硬件外设相关的.c.h文件、编译输出文件、片上外设相关的.c.h文件、用户代码
感觉也有其他的分类方式根据习惯分门别类建立文件就好

函数定义三步
    定义
    声明
    调用


模块化程序的编写
一个模块需要.c和.h两个文件,以seg_led为例:

seg_led.h
#ifndef __SEG_LED_H
#define  __SEG_LED_H
//------------------调用头文件------------------
//------------------引脚定义---------------------
//------------------变量声明---------------------
//------------------函数声明---------------------
#endif

同时在要调用的.c文件中需要引入头文件
seg_led.c
#include "seg_led.h"


补充:
修饰符 extern 的使用
    修饰符 extern 用在变量或者函数的声明前,用来说明“此变量 / 函数是在别处定义的,要在此处引用”。
    举例 1:如果文件 a.c 需要引用 b.c 中变量 int v,就可以在 a.c 中声明 extern int v,然后就可以引用变量 v。
    举例 2:如果文件 a.c 需要引用 b.c 中变量 int v,就可以在 b.h 中声明 extern int v,然后 a.c 调用 b.h 就可以引用变量 v。
    注意 extern 修饰的变量不能赋初值。







回复 支持 反对

使用道具 举报 送花

1

主题

16

回帖

37

积分

新手上路

积分
37
发表于 2024-1-22 15:24:20 | 显示全部楼层
第十四集:矩阵键盘

矩阵按键是我们这个开发版上最后一个IO的一个应用

按键识别原理:端口默认为高电平,实时读取到引脚为低电平是表示按下。再次读取到高电平,表示松开。


第一步:现将P0.0-P0.3输出低电平,P0.6-P0.7输出高电平,如果有按键按下,按下的那一列的IO就会变成低电平,就可以判断出哪一列按下了。


第二步:现将P0.0-P0.3输出高电平,P0.6-P0.7输出低电平,如果有按键按下,按下的那一行的IO就会变成低电平,就可以判断出哪一行按下了。


第三步:行列组合一下就可以判断出是哪个按键按下了。


按键按下后导线导通,哪条线上有高电平,就会被拉低为低电平,从而检测出是哪条线路,二次检查,交叉节点就是有按键按下的按键位置。
矩阵键盘用switch函数实现:

        switch (keystate) //单选开关函数
    {
            case 0x41:        key_val = 1;
                    break;
            case 0x42:        key_val = 2;
                    break;
            case 0x44:        key_val = 3;
                    break;
            case 0x48:        key_val = 4;
                    break;
            case 0x81:        key_val = 5;
                    break;
            case 0x82:        key_val = 6;
                    break;
            case 0x84:        key_val = 7;
                    break;
            case 0x88:        key_val = 8;
                    break;
            default:          key_val = 0;
                    break;
    }



回复 支持 反对

使用道具 举报 送花

1

主题

16

回帖

37

积分

新手上路

积分
37
发表于 2024-1-22 15:27:49 | 显示全部楼层
第十五集:外部中断
中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。
当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。


微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。外部中断就是在单片机的一个引脚上,由于外部因素导致了一个电平的变化(比如由高变低),而通过捕获这个变化,单片机内部自主运行的程序就会被暂时打断,转而去执行相应的中断处理程序,执行完后又回到原来中断的地方继续执行原来的程序。

总的来说就是引脚上的电平变化,然后他就会进入中断。然后中断完子以后再去执行原来的程序。

操作顺序为:
外部中断0:
IT0:中断请求的不同触发条件设置,可选择上升下降沿或者下降沿。
IE0:置位
EX0:中断单独控制开关
EA:中断总开关
外部中断1:
IT1
IE1
EX1
EA
同理再来推理一下INT2,INT3,INT4,他们这边过来只有一条线,只有一个下降沿的符号,且不可以被切换
外部中断x:x=2-4
INTxIF
EXn
EA

void INT0_Init(void)                //外部中断0的初始化,
{
        IT0 = 1;                                 //1:下降沿中断,0:上升或下降沿中断
        EX0 = 1;                                //允许中断,请求源(INT0/P3.2)标志。
        IE0 = 0;                                //清除中断标志位
}

/*                        //复制这个文件的时候,记得把这个中断函数复制到主程序
                        //这个是属于用户型的一个文件(用户需要在里面编写自己的功能),建议将其放在主程序main函数之后,方便更好的引用
void INT0_Isr(void) interrupt 0                //中断号为0,请求源(INT0/P3.2)标志。
{
        //编写用户程序,放在这里仅做提醒
}
*/




回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-6 22:00 , Processed in 0.180676 second(s), 76 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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