t176 发表于 2023-4-10 18:04:59

冲哥STC32G____学习心得

本帖最后由 t176 于 2023-4-11 10:44 编辑

前言:
https://www.stcaimcu.com/static/image/hrline/line2.pnghttps://www.stcaimcu.com/static/image/hrline/line2.pnghttps://www.stcaimcu.com/static/image/hrline/line2.png


首先
感谢冲哥出的STC32G开荒视频,为学习STC32G12K128 提供了学习渠道.
同时也非常感谢STC官方包邮送的屠龙刀.

接下来这帖子将对冲哥32G系列的教学视频,学习过程做一个总结.

https://www.stcaimcu.com/static/image/hrline/line2.pnghttps://www.stcaimcu.com/static/image/hrline/line2.pnghttps://www.stcaimcu.com/static/image/hrline/line2.png

第一步:获取一个32G单片机
可以联系官方客服免费申请(最佳渠道),或者淘宝直接购买
屠龙刀(最佳型号)或者是降龙棍(兼容STC89系列),或者试验箱(反正我手上没有,没有发言权){:sweat:}

屠龙刀:


优点:
引脚齐全,默认没上排针.让用户有最大的发挥空间

降龙棍:



优点:
和STC15系列一样 引脚与STC89系列的引脚标准不一致
官方为了兼容老的89开发板,让这类用户能充分利用现有的硬件资源,对STC32G系列芯片进行了引脚兼容,所以发布了降龙棍系列.做到了上机既用.非常方便
注意:
由于是需要兼容40PIN 引脚,所以难免要阉割部分引脚.这也算是有利有弊把.
还有就是淘宝上买的板子led和电阻不全的问题.卖家回复,出厂就是这样,所以大家在选购降龙棍的时候,一定要积极和卖家沟通.如果学习建议买满电阻和LED 的也就贵几块钱.

总结:建议学习的直接用屠龙刀,试探性尝试性体验32G可以买降龙棍
不过按照STC官方现在这个势头,32G 势必成为主流.建议尽早上手学习.
第二步:上排针
拿到屠龙刀的第一步当然是上排针了,为了学习和使用方便建议公母排
所需物料:

2.54MM 单母排 16PIN *2 (16PIN 是可以衔接在一起的)
2.54MM 单公排 32PIN *2 (这个长点也没事,通常都是可以折断的,建议网购40PIN*2)
2.54 MM 单母排 7PIN *1
接下来放出焊接好的效果图:







1-2集
如果你是从未接触过单片机,建议观看.如果你接触过STC 其他系列
这2集可以直接跳过,理论部分知识.

第三集
关于编译环境的搭建
编译环境使用的keil三合一的环境
详细环境在32G.PDF 第五章
编译、仿真开发环境的建立与 ISP 下载
91页

程序下载我直接使用LINK1D,因为这款下载器,非常的优秀,很方便.可以做到一键下载.
关于不断电 仅仅需要选择ISP 中的 一个选项1

关于2号选项,
是下载完成后LED的状态,相比默认的 下载 更喜欢 第二种,第一种流水灯的效果比较晃眼睛

当然,LINK1D 不仅仅是下载工具.还提供了强大的仿真.在调试硬件的时候,是利器.

顺便再次也说下我自己用的开发环境:
我的搭配是
VS_code编写代码
Keil编译程序:
由于VS高亮语法的特性,我将STC32G.H 的头文件进行了 汉化备注
方便在编写代码时,使用VScode的高亮语法提示



相关头文件我已经发布在 本论坛

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



第4集


关于点亮led灯
冲哥视频中使用的 是三极管驱动LED,
由于手上有一个89开发板,为了方便 直接使用开发板上的LED 好了


现在拿89开发板上的 P10口 作为点灯实现
取下开发板上的芯片,拔掉开发板的电源
首先检查硬件情况,

屠龙刀的VCC 和GND 分别接入开发板的对应VCC 和GND
P10口 对接开发板的P10口,图上可知,LED 之间接了1K 限流电阻
电流安全计算:
电流=电压÷电阻
5V/1000欧姆 =电流:0.005 A=5mA

嗯,在安全范围内,可以使用

屠龙刀代码
#include <stc32G.h>

sbit LED=P1^0;

void main()
{
      P1M0 = 0x00;
      P1M1 = 0x00; // 初始化P1为准双向IO口
      LED = 1; //默认初始化关闭

      while (1)
      {
                LED = 0; //打开LED灯
      }
}


本章代码过于简单,就不进行代码分析了



第5章

在单片机中进制转换的转换为非常重要的章节,因为一组IO 口的组合为16进制(00-FF),单IO口为二进制(也就是01)
在程序编写时,如果进制转换理解不到位,对硬件的操作将会捉襟见肘
如果是刚开始入门单片机 这章要重点学习.进制转换这部分我已经掌握过.就此跳过

给新手一点建议,如果想深刻的理解进制,强烈建议先弄明白理论部分.
通过调试,查看内存数据.结合理论和实践,很快就能弄明白


printf
这是stdio.h C语言标准输入输出库中的输出函数
使用非常灵活,C语言基础部分开篇就会教.在单片机中串口应用时,特别好用

运算符.这个貌似没啥好说的,都是最基础的东西
跳过


第六集
冲哥在第六集列举2种 循环方式
第一种为 while
第二种为 do while
作为控制语句 本人更喜欢while 使用习惯,当然根据业务场景不同有时候 第二种方式使用起来也非常方便

关于delay 函数的使用:
在单片机中延时函数是非常普遍的,但是精度受各种因素影响 会比较差,比较适合对精度不高的业务场景使用
并且在ISP 中可以根据参数直接生成延时函数 非常方便



下面根据冲哥要求完成作业

1.熟悉while的循环过程
2.学会函数的使用(定义、声明、调用)
3.学会新建文件,添加文件路径和添加到工程


课后练习:SOS求救灯光编写
三短三长三短(. . . _ _ _ . . .)


#include <stc32G.h>

sbit LED = P1 ^ 0;

void Delay100ms();
void Delay500ms();
void LED_show_short();
void LED_show_long();

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

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

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

      _nop_();
      _nop_();
      i = 1382398UL;
      while (i)
                i--;
}
void LED_show_short()
{
      Delay100ms();
      LED = 0;
      Delay100ms();
      LED = 1;
}
void LED_show_long()
{

      Delay100ms();
      LED = 0;
      Delay500ms();
      LED = 1;
}
void main()
{
      WTST = 0X00; // 速度最快
      P1M0 = 0x00;
      P1M1 = 0x00; // 初始化P1为准双向IO口
      LED = 1;         // 默认初始化关闭

      while (1)
      {
                LED_show_short();
                LED_show_short();
                LED_show_short();
                Delay100ms();
                LED_show_long();
                LED_show_long();
                LED_show_long();
      }
}
PS:作业统一放置在2楼


第7集

按键的概念和作用总结,
在本章中,
按键作用按下按键将电压 接通gnd 拉低引脚电平
在拉低过程中,由于是机械操作,有电平会波动,也叫抖动

在写代码过程中 经常会使用软件消抖的方式去处理这种情况

教程中冲哥提供了2个软件抖动方案,以应对不同解决方案

核心代码分析:

方式1:
if( KEY == 0 ) //按键是不是低电平(有没有被按下)
{
Delay_ms(10);//延迟10毫秒
if( KEY == 0 )//再次检测是不是低电平(有没有被按下)
{
执行功能
}
}
上述代码使用场景:
适用于 获得连续低电平,比如连加 和连减

方式2:
if( KEY == 0 )//按键是不是低电平(有没有被按下)
{
Delay_ms(10);//延迟10毫秒
if( KEY == 0 )//再次检测是不是低电平(有没有被按下)
{
while(KEY == 0);//程序会持续检测按键是否释放,直到按键释放后才会执行指定功能。这样可以保证在按键按下和释放的期间,程序能够正确地等待用户响应
执行功能
}
}



课后练习:按下按键,切换LED输出不同的效果。
开发板独立键盘


代码:
#include <stc32G.h>

sbit LED = P1 ^ 0;
sbit KEY = P3 ^ 2;

void LED_Type(unsigned char key_type);
void Delay100ms();
void Delay500ms();
void LED_show_short();
void LED_show_long();
void Delay10ms();
void Delay100ms() //@11.0592MHz

{
      unsigned long i;

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

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

      _nop_();
      _nop_();
      i = 1382398UL;
      while (i)
                i--;
}
void LED_show_short()
{
      Delay100ms();
      LED = 0;
      Delay100ms();
      LED = 1;
}
void LED_show_long()
{

      Delay100ms();
      LED = 0;
      Delay500ms();
      LED = 1;
}

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

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



void LED_Type(unsigned char key_type) // 根据按钮状态显示 快慢闪烁
{

      static bit temp; //

      if (key_type == 1 || key_type == 0)//只有值是0或者1时,才切换状态
      {
                temp = ~temp; // 翻转静态临时状态
      }

      if (temp)
      {

                LED_show_short();
      }
      else
      {

                LED_show_long();
      }
}
void main()
{
      WTST = 0X00; // 速度最快
      P1M0 = 0x00;
      P1M1 = 0x00; // 初始化P1为准双向IO口
      P3M0 = 0x00; P3M1 = 0x00; //初始化P1为准双向IO口

      LED = 1;         // 默认初始化关闭

      while (1)
      {
                if (KEY == 0)
                {
                        Delay10ms();
                        if (KEY == 0)
                        {
                              while (KEY == 0);
                              LED_Type(KEY);
                        }
                }
                LED_Type(3);//传入非0或者1 的无效值,则LED 显示状态不变
      }
}

第8集

关于蜂鸣器,看了冲哥的蜂鸣器电路


这电路图的重点是 S8550三极管
信号引脚 (小电流)推动三极管 驱动蜂鸣器(大电流),因为蜂鸣器所用的电流比较大,如果直接将它接在IO口上,是非常不明智的,稳定性不说,非常有可能会烧毁IO口.
冲哥这个电路图 是非常标准的接法.

好了,接下来看看作业:

课后练习:增加按键3,按下后表示启动,选择的对应的功能的LED持续闪烁,表示正在工作,且在工作的时候无法切换功能



static/image/hrline/1.gif

再看看我开发板上的蜂鸣器 ,触发三极管接是P23

看下独立键盘,上次用的P32这次就加一个按键P33好了



#include <stc32G.h>

sbit LED = P1 ^ 0;                // LED灯引脚
sbit WORK_LED = P1 ^ 7; // 工作状态
sbit KEY = P3 ^ 2;                // 切换闪灯模式
sbit KEY2 = P3 ^ 3;                // 按键2,控制工作状态
sbit BEEP = P2 ^ 3;                // 蜂鸣器引脚

bit working = 0; // 正在工作=1,不在工作=0,默认不工作

void LED_Type(unsigned char key_type);
void Delay100ms();
void Delay500ms();
void LED_show_short();
void LED_show_long();
void Delay10ms();
void Delay100ms() //@11.0592MHz

{
      unsigned long i;

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

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

      _nop_();
      _nop_();
      i = 1382398UL;
      while (i)
                i--;
}
void LED_show_short()
{
      Delay100ms();
      LED = 0;
      Delay100ms();
      LED = 1;
}
void LED_show_long()
{

      Delay100ms();
      LED = 0;
      Delay500ms();
      LED = 1;
}

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

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

void LED_Type(unsigned char key_type) // 根据按钮状态显示 快慢闪烁
{

      static bit temp; //

      if (key_type == 1 || key_type == 0) // 只有值是0或者1时,才切换状态
      {
                temp = ~temp; // 翻转静态临时状态
      }

      if (temp)
      {

                LED_show_short();
      }
      else
      {

                LED_show_long();
      }
}
void main()
{
      WTST = 0X00; // 速度最快
      P1M0 = 0x00;
      P1M1 = 0x00; // 初始化P1为准双向IO口
      P2M0 = 0x00;
      P2M1 = 0x00; // 初始化P2为准双向IO口

      P3M0 = 0x00;
      P3M1 = 0x00; // 初始化P1为准双向IO口

      LED = 1;// 默认初始化关闭
      BEEP = 1; // 默认关闭蜂鸣器
      while (1)
      {
                if (KEY == 0) // 这是切换闪灯模式
                {
                        Delay10ms();
                        if (KEY == 0 && working == 0) // 在非工作状态下才可以切换
                        {
                              while (KEY == 0)
                                        ;
                              LED_Type(KEY);
                        }
                }
                if (KEY2 == 0) // 这是工作状态
                {
                        Delay10ms();
                        if (KEY2 == 0)
                        {
                              while (KEY2 == 0)
                                        ;
                              working = ~working; // 开始或停止工作状态状态
                              if (working)
                              {
                                        WORK_LED = 0; // 打开指示灯
                                        //开始工作,短鸣2次
                                        Delay100ms();
                                        BEEP = 1;
                                        Delay100ms();
                                        BEEP = 0;
                                        Delay100ms();
                                        BEEP = 1;
                                        Delay100ms();
                                        BEEP = 0;
                                        Delay100ms();
                                        BEEP = 1;
                              }
                              else
                              {
                                        WORK_LED = 1; // 关闭指示灯
                                        //结束工作,长鸣一次
                                        Delay100ms();
                                        BEEP = 0;
                                        Delay500ms();
                                        BEEP = 1;
                              }
                        }
                }

                LED_Type(3); // 传入非0或者1 的无效值,则LED 显示状态不变
      }
}

第九集
PS:由于上传的视频无法正常播放,这一集开始将不再上传作业视频

关于数码管,数码管分共阴和共阳极 .本质是一样的 只是接线方式不同,同时也决定了码表的不一致
下面是 码表
共阳极:
unsigned char 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,//熄灭
                0xFF//自定义

                         };
共阴极:
unsigned char 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,//熄灭
                0x00//自定义

                         };
下面是开发板上的数码管原理图


相关案列代码:
/*
降龙棍~单位数码管_静态扫描最简单的案列

~74HC573,4位数码管接线在P0口,数码管采用共阴极

同步89开发板的时钟,这里为了与89开发板同步做实验统一用11.0592晶振
*/

#include <STC32G.H>
/*数码管段码表*/
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,//熄灭
                0x00//自定义

                         };

void Delay500ms();
sbit DUAN = P2 ^ 6; // 定义段引脚
sbit WEI =P2^7; //定义位引脚



void main()
{
         
      int i;
      P0M0 = 0x00;
      P0M1 = 0x00;//将IO 设置为准双向模式

      P2M0 = 0x40;
      P2M1 = 0x00; // 设置为推挽输出模式,给74HC573上点激活Q0-Q7口

      P0=0X00; //初始化IO口上低电平
      P2=0X00;//段和位全部置低
      P23 =0X01; //89开发板上的关闭蜂鸣器
      WTST =0X00;//延时寄存器初始化

      for ( i = 0; i < 10; i++)
      {
                              //位选
                WEI =1;
                P0= 0xfe;
                WEI =0x00;
                //段选
                DUAN =1;
                P0=leddata;
                DUAN =0;
                Delay500ms();

      }
         
               
      // for ( i = 9; i >= 0; i--)
      // {
      //                         //位选
      //         WEI =1;
      //         P0= 0xfe;
      //         WEI =0x00;
      //         //段选
      //         DUAN =1;
      //         P0=leddata;
      //         DUAN =0;
      //         Delay500ms();

      // }

}


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

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


第10集

这一集冲哥对数码管动态扫描案列做了讲解,
这里使用一个简单的案列实现动态扫描
/*
降龙棍~8位数码管_动态扫描

~74HC573,4位数码管接线在P0口,数码管采用共阴极

同步89开发板的时钟,这里为了与89开发板同步做实验统一用11.0592晶振
*/

#include <STC32G.H>
#define OFF 0X00
#define ON 0xff
#define SMG_VAL_PORT P0                // 数码管端口
#define Ulong unsigned long // 无符号长整型

/*数码管段码表*/
unsigned char code DUAN_data[] = {

      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, // 熄灭
      0x00// 自定义

};
/*数码管位表*/
unsigned char code WEI_data[] = {
      0xfe, // 1111 1110      b
      0xfd, // 1111 1101      b
      0xfb, // 1111 1011      b
      0xf7, // 1111 0111      b
      0xef, // 1110 1111      b
      0xdf, // 1101 1111      b
      0xbf, // 1011 1111      b
      0x7f// 0111 1111      b
};

// 函数声明

void Show_Duan_val(char DuanNum, char val);
void Convert_Display(Ulong VAL);
void Delay5ms();
void Delay1us();
bit Delay_chang(Ulong val);
sbit DUAN = P2 ^ 6; // 定义段引脚
sbit WEI = P2 ^ 7;      // 定义位引脚
void main()
{

      int i = 0;
      int j = 0;
      SMG_VAL_PORT = 0x00;
      P0M0 = 0x00;
      P0M1 = 0x00; // 将IO 设置为准双向模式
      WTST = 0X00;
      SMG_VAL_PORT = 0x00;
      P2M0 = 0x40;
      P2M1 = 0x00;                // 设置为推挽输出模式,给74HC573上点激活Q0-Q7口
      P2 = OFF;                        // 段位口初始化
      P23 = 1;                        // 关闭蜂鸣器
      SMG_VAL_PORT = OFF; // P0口初始化
      while (1)
      {
                if (Delay_chang(10) == 1)
                { // 数值变化控制

                        Convert_Display(j++); // 如果达到阈值将数值+1
                }
                else
                {
                        Convert_Display(j); // 只显示,不增加数值
                }
      }
}

/*扫描频率*/
bit Delay_chang(Ulong val)
{
      static Ulong timetry = 0;
      timetry++;
      Delay1us();
      if (timetry == val)
      {
                timetry = 0;
                return 1;
      }
      else
      {
                return 0;
      }
}
/*数值转换显示函数*/
void Convert_Display(Ulong VAL)
{
      char i;
      char VAL_arr;
      char count = 0;

      while (VAL != 0)
      {
                VAL_arr = VAL % 10;
                VAL = VAL / 10;
                count++;

                for (i = 0; i < count; i++)
                {
                        Show_Duan_val((char)(7 - i), VAL_arr);
                }

                Delay5ms();
      }
}
/*
//显示单位数码管
*参数1:Duan_Num,需要显示在第几位数码管上_取值范围:0-8
*参数2:val,需要显示的数字
*/
void Show_Duan_val(char DuanNum, char val)
{

      // 选择位
      WEI = 1;
      SMG_VAL_PORT = WEI_data;
      WEI = 0;

      // 选择段,显示段
      DUAN = 1;
      SMG_VAL_PORT = DUAN_data;
      DUAN = 0;
}

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

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

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

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


STC32g12k128是一款基于超高速32位8051内核的单片机,它具有多种数字和模拟外设,包括5个16位定时器。定时器可以用来实现计时、延时、PWM输出、串口通信等功能。定时器的初始化和中断配置需要使用STC32G库函数2,其中Timer_Inilize()函数用来设置定时器的工作模式、时钟源、初值和运行状态,NVIC_Timerx_Init()函数用来设置定时器的中断使能和优先级。在STC32G_Timer_Isr.c文件中,可以编写相应的中断服务函数来实现具体的功能



单片机定时器/计数器工作方式控制方式工作模式计数脉冲来源计数模式分频
T0定时器/计数器TMOD寄存器中的C/T位模式0:16位自动重装载模式模式1:16位不可重装载模式模式2:8位自动重装载模式模式3:16位自动重装载模式(不可屏蔽中断)系统时钟或外部引脚不分频
T1定时器/计数器TMOD寄存器中的C/T位模式0:16位自动重装载模式模式1:16位不可重装载模式模式2:8位自动重装载模式系统时钟或外部引脚不分频
T2定时器/计数器AUXR寄存器中的T2_C/T位16位自动重装载模式系统时钟或外部引脚分频可选择系统时钟/12或不分频
T3定时器/计数器T4T3M寄存器中的T3_C/T位16位自动重装载模式系统时钟或外部引脚分频可选择系统时钟/12或不分频
T4定时器/计数器T4T3M寄存器中的T4_C/T位16位自动重装载模式系统时钟或外部引脚分频可选择系统时钟/12或不分频











符号地址B7B6B5B4B3B2B1B0
TCON88HTF1TR1TF0TR0IE1IT1IE0IT0



寄存器/控制位描述
TCON定时器0/1控制寄存器
TF1T1溢出中断标志,计数溢出时硬件将TF1置1,请求中断
TR1定时器T1的运行控制位,软件置位和清零。GATE=0时,TR1=1启动T1计数;GATE=1时,TR1=1且INT1输入高电平时才启动T1计数
TF0T0溢出中断标志,计数溢出时硬件将TF0置1,请求中断
TR0定时器T0的运行控制位,软件置位和清零。GATE=0时,TR0=1启动T0计数;GATE=1时,TR0=1且INT0输入高电平时才启动T0计数
IE1外部中断1请求源标志,IE1=1时,外部中断向CPU请求中断
IT1外部中断源1触发控制位,IT1=0时,上升沿或下降沿均可触发外部中断1;IT1=1时,外部中断1仅下降沿触发
IE0外部中断0请求源标志,IE0=1时,外部中断向CPU请求中断
IT0外部中断源0触发控制位,IT0=0时,上升沿或下降沿均可触发外部中断0;IT0=1时,外部中断0仅下降沿触发







符号地址B7B6B5B4B3B2B1B0
TMOD89HT1_GATET1_C/TT1_M1T1_M0T0_GATET0_C/TT0_M1T0_M0




符号功能
T1_GATE控制定时器1,只有在INT1高电平及TR1置1时才可打开
T0_GATE控制定时器0,只有在INT0高电平及TR0置1时才可打开
T1_C/T控制定时器1用作定时器或计数器
T0_C/T控制定时器0用作定时器或计数器
T1_M1定时器1模式选择
T1_M0定时器1模式选择
T0_M1定时器0模式选择
T0_M0定时器0模式选择






T0_M1 T0_M0定时器0工作模式
0 016位自动重载模式,内部系统时钟÷12
0 116位不自动重载模式,从0开始计数
1 08位自动重载模式,TL0计数值溢出自动将TH0中的重载值装入TL0中
1 1不可屏蔽中断的16位自动重载模式,用于操作系统的系统节拍定时器






T1_M1 T1_M0定时器1工作模式
0 016位自动重载模式,内部系统时钟÷12
0 116位不自动重载模式,从0开始计数
1 08位自动重载模式,TL1计数值溢出自动将TH1中的重载值装入TL1中
1 1T1停止工作








定时器 0 模式 0(16 位自动重装载模式)


项目详细描述
标题定时器 0 模式 0(16 位自动重装载模式)
GATE当 GATE=0(TMOD.3)时,如 TR0=1,则定时器计数。GATE=1 时,允许由外部输入 INT0 控制定时器 0,这样可实现脉宽测量
TR0TCON 寄存器内的控制位,控制定时器工作/停止
TCON寄存器各位的具体功能描述见上节 TCON 寄存器的介绍
C/T当 C/T=0 时,多路开关连接到系统时钟的分频输出,T0 对内部系统时钟计数,T0 工作在定时方式。当 C/T=1 时,多路开关连接到外部脉冲输入 P3.4/T0,即 T0 工作在计数方式
AUXR.7T0x12=0 时 T0 工作在 12T 模式;T0x12=1 时 T0 工作在 1T 模式
T0 Pin当 AUXR.7/T0x12=1 时,T0 Pin 用作输入脉冲计数
TF0 的溢出置位 TF0
TH0定时器 0 的高 8 位
TL0定时器 0 的低 8 位
T0CLKO当 T0CLKO/INT_CLKO.0=1 时,P3.5/T1 管脚配置为定时器 0 的时钟输出 T0CLKO,输出时钟频率为 T0 溢出率/2
Interrupt当定时器 0 溢出时触发中断
P3.5T0CLKO 的输出管脚
Toggle当定时器 0 溢出时,P3.5 反转
SYSclk系统时钟
TM0PST0 的预分频器,实际分频值为 TM0PS + 1
RL_TH0隐藏的 TH0 寄存器,当 TR0=1 时,对 TH0 写入内容实际上是写入 RL_TH0 中,可以实现 16 位重装载定时器
RL_TL0隐藏的 TL0 寄存器,当 TR0=1 时,对 TL0 写入内容实际上是写入 RL_TL0 中,可以实现 16 位重装载定时器



定时器 0 模式 1(16位不可重装载模式)


模式/功能描述
定时器/计数器定时器/计数器0
模式16位不可重装载模式
计数速率12T模式或1T模式(由AUXR寄存器的T0x12位决定)
溢出标志TF0(由TH0计数溢出置位)
计数控制TR0(TCON寄存器内控制位)
外部输入控制GATE(TMOD寄存器的第3位)
外部脉冲输入P3.4/T0
内部系统时钟计数SYSclk
分频输出÷12
切换控制P3.5(用于T0CLKO输出的切换控制)
中断INT0
TL08位,由TL0的8位构成
TH08位,由TH0的8位构成,TL0的8位溢出向TH0进位
T0CLKOT0时钟输出
AUXR.7/T0x12=0T0工作在12T模式
AUXR.7/T0x12=1T0工作在1T模式



定时器 0 模式 2(8 位自动重装载模式)


内容值
定时器模式2
定时器溢出处理置位 TF0,重新装载 TH0 的值到 TL0
TH0 值重载时TH0 值不变,由软件预置
T0CLKO/INT_CLKO.0=1 时的 P3.5/T1 管脚配置T0CLKO,时钟输出
输出时钟频率(T0CLKO)T0溢出率/2
定时器/计数器 T0 工作模式1T 模式和 12T 模式
T0 工作在 1T 模式时的输出时钟频率(SYSclk)/(TM0PS+1)/(256-TH0)/2
T0 工作在 12T 模式时的输出时钟频率(SYSclk)/(TM0PS+1)/12/(256-TH0)/2
定时器/计数器 T0 是对外部脉冲输入计数时的输出时钟频率(T0_Pin_CLK) / (256-TH0)/2
C/T 值0(对内部系统时钟计数)和 1(对外部脉冲输入计数)
T0_Pin_CLK 值外部脉冲输入频率
TM0PS+1 值定时器/计数器 T0 的分频系数(可由软件设置)

定时器 0 模式 3(不可屏蔽中断 16 位自动重装载,实时操作系统节拍器)



标题定时器0模式3(不可屏蔽中断16位自动重装载,实时操作系统节拍器)
工作原理与工作模式0相同,但只需允许ET0/IE.1(定时器/计数器0中断允许位),不需要允许EA/IE.7(总中断使能位)
中断特性不可屏蔽中断,优先级最高,不能被任何中断打断;该中断打开后不受EA/IE.7和ET0控制,清零EA或ET0都不能关闭此中断
控制信号TR0-定时器/计数器0运行控制位;TF0-定时器/计数器0中断标志位;GATE-计数器0的控制信号;INT0-外部中断0的中断标志位;TL0/RL_TH0/RL_TL0-定时器/计数器0的计数器初值和重装载值;T0CLKO-定时器0的时钟输出
其他此模式下的定时器/计数器0可用作实时操作系统的节拍器;不需要允许EA/IE.7(总中断使能位)即可打开中断,节约中断开销





定时器 1 模式 0(16 位自动重装载模式)



模式16 位自动重装载模式
TR1定时器计数开关
GATE允许外部输入 INT1 控制定时器 1
C/T多路开关连接到系统时钟的分频输出或外部脉冲输入 P3.5/T1
T1 模式定时方式或计数方式
T1 计数速率12T 模式或 1T 模式
T1 速率设置特殊功能寄存器 AUXR 中的 T1x12 决定
隐藏寄存器RL_TH1 与 TH1 共有同一个地址,RL_TL1 与 TL1 共有同一个地址
写入 RL_TH1 和 RL_TL1当 TR1=0 即定时器/计数器 1 被禁止工作时
写入 TH1 和 TL1当 TR1=1 即定时器/计数器 1 被允许工作时
TH1 和 TL1 内容读 TH1 和 TL1 的内容时,所读的内容就是 TH1 和 TL1 的内容,而不是 RL_TH1 和 RL_TL1 的内容
定时器 1 模式 1的溢出会自动将的内容重新装入
其中还有一些参数需要补充:


参数描述
TF1定时器 1 溢出标志
TCON包含 TR1 和 TF1 控制位
TH1定时器 1 的高 8 位计数值
TL1定时器 1 的低 8 位计数值
P3.5/T1外部脉冲输入口
T1CLKO定时器 1 的时钟输出口
TMOD定时器/计数器模式寄存器
SYSclk系统时钟频率
TM1PST1 时钟分频系数
T1x12T1 计数速率设置位
其中 TCON 寄存器各位的具体功能描述不在本文中提供。


定时器 1 模式 1(16 位不可自动重装载模式)





模式定时器/计数器1
TMOD00B
TH1/TL1初始值用户设定
溢出TH1/TL1溢出置位TF1,并自动将RL_TH1/RL_TL1的内容重新装入TH1/TL1
TR1TCON寄存器内的控制位
GATE允许由外部输入INT1控制定时器1
C/T多路开关连接到系统时钟的分频输出或外部脉冲输入P3.5/T1
T1CLKO/INT_CLKO.1当T1CLKO/INT_CLKO.1=1时,P3.4/T0管脚配置为定时器1的时钟输出T1CLKO。输出时钟频率为T1溢出率/2
T1速率12T模式或1T模式,由特殊功能寄存器AUXR中的T1x12决定
隐藏寄存器RL_TH1和RL_TL1
读取寄存器读取TH1和TL1的内容
注意:当T1工作在1T模式时的输出时钟频率和当T1工作在12T模式时的输出时钟频率的计算


定时器 1 模式 2 (8 位自动重装载模式)





模式TCON.TR1TMOD.M1TMOD.M0TCON.TF1TCON.GATET1计数方式T1计数速率T1计数值
210101计数12T/1TP3.5/T1
注解:
[*]TCON.TR1:定时器/计数器 1 启动控制位,当 TR1=1 时开始计数,TR1=0 时停止计数。
[*]TMOD.M1/M0:定时器/计数器 1 工作模式选择位,当 M1/M0=01 时工作在模式 2。
[*]TCON.TF1:定时器/计数器 1 溢出标志位,定时器/计数器 1 的计数值溢出后,TF1 置 1。在模式 2 中,TF1 为只读标志位,不能被软件清除。
[*]TCON.GATE:定时器/计数器 1 的门控控制位,当 GATE=1 时允许外部输入 INT1 控制定时器 1,当 GATE=0 时,忽略 INT1 输入,定时器/计数器 1 一直计数。
[*]T1 计数方式:在模式 2 中,定时器/计数器 1 工作在计数方式,即通过外部脉冲输入 P3.5/T1 进行计数。
[*]T1 计数速率:T1 的计数速率由特殊功能寄存器 AUXR 中的 T1x12 决定,如果 T1x12=0,则 T1 工作在 12T 模式;如果 T1x12=1,则 T1 工作在 1T 模式。
[*]T1 计数值:T1 计数值由 TH1 和 TL1 两个寄存器组成,最大计数值为 65535,溢出后会重新装载 RL_TH1 和 RL_TL1 中的值。

在模式 2 中,定时器/计数器 1 工作在外部事件计数器模式,通过 P3.5/T1 外部脉冲输入进行计数,当 T1 计数值溢出时,TF1 置 1,并重新装载 RL_TH1 和 RL_TL1 中的值。在此模式下,TL1 和 TH1 寄存器没有定时器的功能,只用于存储计数值。




STC32G是一款单片机,其中定时器分频、预分频寄存器TM0PS和系统时钟SYSclk之间的关系如下:

定时器分频指的是将系统时钟SYSclk进行分频后再输入到定时器中,以控制定时器的时钟频率,从而控制定时器计数的速度。定时器分频的值通过设置预分频寄存器TM0PS来实现,TM0PS的值越大,分频越多,计数速度越慢。

预分频寄存器TM0PS是用于控制定时器0(Timer0)的预分频值的寄存器,它的值范围为0-255。预分频值为n时,定时器0的时钟频率为SYSclk/(n+1)。例如,当TM0PS的值为3时,定时器0的时钟频率为SYSclk/4。

系统时钟SYSclk是单片机内部的时钟信号,它的频率由外部晶体振荡器或内部时钟发生器提供,其值可以通过相关的寄存器进行设置。在STC32G中,SYSclk的频率可以从4MHz到24MHz,取决于系统的硬件设置。

定时时间的计算方法如下:

设定时器的分频值为n,定时时间为t,系统时钟频率为f,则定时器的计数频率为f/(n+1)。则定时器计数t秒所需的计数值为t*f/(n+1)。

例如,假设定时器0的预分频值TM0PS为3,系统时钟频率为12MHz,需要定时1秒,则定时器0的计数频率为12MHz/(3+1)=3MHz,需要计数3,000,000次,即定时器计数寄存器TH0和TL0的初值为65536-3000000=27936(0x6D00)。

定时范围的计算方法如下:

设定时器的分频值为n,定时范围为t1到t2,系统时钟频率为f,则定时器的计数范围为[(t1f)/(n+1), (t2f)/(n+1)]。

例如,假设定时器0的预分频值TM0PS为3,系统时钟频率为12MHz,需要定时0.1秒到1秒之间的时间,则定时器0的计数范围为[(0.112MHz)/(3+1), (112MHz)/(3+1)],即。定时范围内的任何时间都可以表示为定时器0计数寄存器TH0和TL0的初值的不同组合。



在充分理解定时器后,计数器就变的非常简单.
只要留意寄存器TMOD的配置就可以轻松实现,详细参考32G.PDF 14章节
需要注意的是:
从实践中得出结论,在使用计数器的时候.需要注意脉冲抖动.以确保记数的精准度



这一课,非常的重要,可以结构清晰的代码整理方案,决定了代码的可维护性,与编写速度
我从这课收益匪浅
首先说说,分文件编写关于H头文件和C文件的关联
在企业开发过程中,如果还是使用之前的代码编写风格一个main.c 撸到底,那么会被同事鄙视.
在面试时,如果写出这样一个单文件的MOD,面试官马上就会知道你的码龄
并且这种单文件的编写风格我们有一个比较形象的 称谓 叫猪大肠程序.很形象就是猪大肠一样一节节的.而且一撸到底.
企业非常鄙视这种代码书写习惯
所以分文件编写是 程序员必须掌握的


然后说说 代码注释.
一个强大的代码注释决定了 程序的可读性.没有代码注释的代码,是很容易挨主管的批评的.
冲哥在这一集中 对代码注释做了很详细的解说.非常赞.

根据冲哥的视频学习我将学习到的知识成立成VScode 的脚本以便更加方便的应用
下面我放出 注释脚本
{
      "函数备注": {
                "prefix": "/?", //这里是快捷键方法
               
                "body": [
                        "/*",
                        "*----------------------------------------------------------------------------------------------",
                        "* 函数名称:$CLIPBOARD",
                        "* 函数功能:",
                        "* 入口参数:@",
                        "* 函数返回:@",
                        "* 当前版本: Ver1.0",
                        "* 修改时间:$CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",
                        "* 作者:t176#qq.com",
                        "* 创建时间:$CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",
                        "-----------------------------------------------------------------------------------------------",
                        "*/"
                ],
                "description": "函数注释"
      },
      "程序备注": {
                "prefix": "/.", //这里是快捷键方法
                "body": [
                        "/*",
                        "*----------------------------------------------------------------------------------------------",
                        "* 作者:t176",
                        "* 邮箱:t176#qq.com",
                        "* 程序功能:",
                        "* 备注:",
                        "*      引脚定义:",
                        "* 当前版本: Ver1.0",
                        "* 最后维护时间:$CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",
                        "-----------------------------------------------------------------------------------------------",
                        "*/"
                        
                ],
                "description": "程序备注"
      },
      "单行备注": {
                "prefix": "/;", //这里是快捷键方法
                "body": [
                        "/*--$0--*/"
                        
                ],
                "description": "单行备注"
      },
      "头文件模板": {
                "prefix": "/|", //这里是快捷键方法
                "body": [
                        "/*",
                        "*----------------------------------------------------------------------------------------------",
                        "* 作者:t176",
                        "* 邮箱:t176#qq.com",
                        "* 说明:$TM_FILENAME头文件",
                        "* 备注:",
                        "       :null",
                        "* 当前版本: Ver1.0",
                        "* 最后维护时间:$CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",
                        "*----------------------------------------------------------------------------------------------",
                        "*/\n\n\n\n\n\n",
                        "#ifndef __${TM_FILENAME_BASE/(.*)/${1:/upcase}/}_H__",
                        "#define __${TM_FILENAME_BASE/(.*)/${1:/upcase}/}_H__\n\n\n",
                        "/*--------------宏定义--------------*/\n\n\n",
                        "/*--------------变量定义--------------*/\n\n\n",
                        "/*--------------函数声明--------------*/\n\n\n",

                        "#endif",


                        
                ],
                "description": "头文件模板"
      },
}

上面代码段,的使用方法非常简单.只要在VScode中--设置---导入代码段就可以了



使用方法|:







第十四集
通过上集的学习,和这集的知识写一段矩阵键盘的应用




SYS.H
//--------------------------------------------------------------
/*本代码严格遵循微软代码风格约定
//---------------------------------------------------------------
代码风格约定:
局部变量:   小写可(加下划线)
    float sum = 0.0f;
    float sum_count = 0;


全局变量:g_开头加小驼峰(可加下划线)
    int g_maxStudents = 100;
    float g_averageScore = 0.0f;


函数:    大驼峰(可加下划线)
int CalculateSum(int x, int y);
int Calculate_Sum(int x, int y);


宏定义:全大写
#define PI 3.14159265358979323846

*/
//----------------------------------------------------------------
/*程序说明:

降龙棍~矩阵键盘按键响应数码管,显示每个键值
*引脚说明:
P46(30) 行S6,7,8,9
P47(31) 行S10,11,12,13
P32 行S14,15,16,17
P33 行S18,19,20,21

P34 列S6,10,14,18
P35 列S7,S11,15,19
P36 列S8,12,16,20
P37 列S9,13,17,21

数码管位:P27
数码管段:P26


~74HC573,4位数码管接线在P0口,数码管采用共阴极

同步89开发板的时钟,这里为了与89开发板同步做实验统一用11.0592晶振
*/

#ifndef __SYS_H_
#define __SYS_H_
#include <STC32G.H>

/*定义无符号整数类型*/ #define ULONG unsigned long
/*定义数码管端口*/ #define B8LED P0
/*定义矩阵键盘端口*/ #define KEYPORT P3

unsigned char code g_duan_Data[] = {
    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, // 熄灭
    0x00// 自定义

};
/*数码管位表*/
unsigned char code g_wei_Data[] = {
    0xfe, // 1111 1110b
    0xfd, // 1111 1101b
    0xfb, // 1111 1011b
    0xf7, // 1111 0111b
    0xef, // 1110 1111b
    0xdf, // 1101 1111b
    0xbf, // 1011 1111b
    0x7f// 0111 1111b
};
/*数据存储*/ ULONG g_num = 0;

/*段引脚*/ sbit g_duan = P2 ^ 6;
/*位引脚*/ sbit g_wei = P2 ^ 7;

/*矩阵键盘引脚定义*/
// 编程框架函数声明

void Sys_Init();
void Sys_Draw();
void User_Updata();
void Sys_Updata();

// 用户函数声明

void Dis_Show(char wei_flag, char val);
void Dis_Scan(ULONG val);
void Keys_Scan();
void Delay5ms();
char Get_Row();
char Get_Col();




#endif

main.c

#include "sys.h"

void main()

{

    // 采用框架式编程
    //1.定义数据
    //2.系统初始化数据
    Sys_Init(); // 初始化
    while (1)
    {
      // 3.系统数据绘制
      Sys_Draw();
      // ----------------------------------------4.数据更新
      // 4.1用户干预更新数据
      User_Updata();
      // 4.2 系统自动更新数据
      Sys_Updata();
    }
}
// 系统式编程框架-----------------------------------------------
/*初始化函数*/
void Sys_Init()
{
    // 准双向IO口定义
    P2M0 = 0x00;
    P2M1 = 0x00; // P2口设置为准双向IO口,74H芯片
    P0M0 = 0x00;
    P0M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    // 初始化
    P2 = 0xff; // 设置为高电平
    P3 = 0Xff;
    P4 = 0Xff;
    P0 = 0x00;
    WTST = 0X00; // 延时等待控制器
}
/*绘制处理数据*/
void Sys_Draw()

{
    Dis_Scan(g_num);
}

/*用户干预更新数据*/
void User_Updata()
{

    Keys_Scan();
}
/*系统更新数据*/
void Sys_Updata()
{
}
// 下面数用户函数实现区域-----------------------------------

/*键盘扫描*/
void Keys_Scan()
{
    int x, y;                   // 矩阵键盘的X和Y 轴
    unsigned char temp_row = 0; // 行数据
    unsigned char temp_col = 0; // 列数据
    int key_tables={//这是一个矩阵键盘对应的键值表
      0,1,2,3,
      4,5,6,7,
      8,9,10,11,
      12,13,14,15
    };

    temp_row = (unsigned char)Get_Row(); // 扫描行
    temp_col = (unsigned char)Get_Col(); // 扫描列
    if (temp_row != 99)//如果返回99说明按键并未被按下
    {
      switch (temp_row)//对获得的值取x坐标
      {
      case 0X07:
            x = 0;
            break;
      case 0X0B:
            x = 1;
            break;
      case 0X0D:
            x = 2;
            break;
      case 0X0E:
            x = 3;
            break;
      default:
            break;
      }
    }
    if (temp_col != 99)//对获得的值取y坐标
    {
      switch (temp_col)
      {
      case 0XE0:
            y = 0;
            break;
      case 0XD0:
            y = 1;
            break;
      case 0XB0:
            y = 2;
            break;
      case 0X70:
            y = 3;
            break;

      default:
            break;
      }
    }

    if(temp_row!=99 &&temp_row!=99)//如果确定按键已经被按下,
    g_num =key_tables ;//给全局变量赋值
}

/*数码管单位显示
*参数1:wei_flag: 显示在哪一位上
*参数2:val: 需要显示的值
*/
void Dis_Show(char wei_flag, char val)
{
    B8LED = 0;                  // 清除段码
    g_wei = 1;                  // 打开位锁存器
    B8LED = g_wei_Data; // 选择数码管位
    g_wei = 0;                  // 关闭位锁存器
    B8LED = 0;                  // 清除段码
    g_duan = 1;                   // 打开段锁存器
    B8LED = g_duan_Data;   // 显示段数据
    g_duan = 0;                   // 关闭段锁存器
}
/*数码管动态扫描
*参数1:val需要显示的数据
*/
void Dis_Scan(ULONG val)
{
    char val_arr; // 储存每个位置的数组
    char count = 0;// 初始化遍历记录变量为0

    if (val == 0)
    {                   // 如果传入的值为0
      Delay5ms();   // 消除鬼影
      Dis_Show(7, 0); // 直接输出数码管显示结果为0
    }
    else
    {
      while (val != 0)
      {
            val_arr = val % 10;
            val /= 10;
            count++;
            Delay5ms(); // 消除鬼影
            Dis_Show((char)(8 - count), val_arr);
      }
    }
}
/*返回矩阵键盘按下行码*/
char Get_Row()
{
    P46 = 1;
    P47 = 1;
    P3 = 0X0f;
    P30 = P46; // P30 位置在降龙棍上被阉割,被替换为P46
    P31 = P47; // P31 位置在降龙棍上被阉割,被替换为P47

    if (P3 != 0x0f) // 行扫描
    {
      return P3;
    }
    return 99;//说明按键未被按下
}
/*返回矩阵键盘按下列码*/
char Get_Col()
{
    P3 = 0Xf0;
    P46 = 0;
    P47 = 0;
    P30 = P46; // P30 位置在降龙棍上被阉割,被替换为P46
    P31 = P47; // P31 位置在降龙棍上被阉割,被替换为P47

    if (P3 != 0xf0) // 行扫描
    {
      return P3;
    }
    return 99;//说明按键未被按下
}
void Delay5ms() //@11.0592MHz
{
    volatile unsigned long i;

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


config.h
//--------------------------------------------------------------
/*本代码严格遵循微软代码风格约定
//---------------------------------------------------------------
代码风格约定:
局部变量:   小写可(加下划线)
    float sum = 0.0f;
    float sum_count = 0;


全局变量:g_开头加小驼峰(可加下划线)
    int g_maxStudents = 100;
    float g_averageScore = 0.0f;


函数:    大驼峰(可加下划线)
int CalculateSum(int x, int y);
int Calculate_Sum(int x, int y);


宏定义:全大写
#define PI 3.14159265358979323846

*/

/*
*----------------------------------------------------------------------------------------------
* 作者:t176
* 邮箱:t176@qq.com
* 程序功能:普通IO_P35口低电平中断测试
* 备注:
*      引脚定义:P35
* 当前版本: Ver1.0
* 最后维护时间:2023/03/22 09:58:50
-----------------------------------------------------------------------------------------------
*/

#ifndef __CONFIG_H__
#define __CONFIG_H__
#include <STC32G.H>

/*定义无符号整数类型*/ #define ULONG unsigned long

extern ULONG g_num; // 修饰一个全局变量g_mun

// 编程框架函数声明

void Sys_Init();
void Sys_Draw();
void User_Updata();
void Sys_Updata();

// 用户函数声明

#endifdisplay.h
#ifndef __DISPLAY_H__
#define __DISPLAY_H__
#include "config.h"


#define SEGPORT P0

void Seg_Scan(ULONG val);
void Show_Duan(char wei, char val);
void Delay1ms();
#endifioexit.h
#ifndef __IOEXIT_H__
#define __IOEXIT_H__
#include "config.h"

extern ULONG g_num; //修饰一个全局变量g_mun
void Io_Init();
void Io_Break_Fun();
#endifdisplay.c
#include "display.h"

sbit g_duan = P2 ^ 6; // 定义段引脚
sbit g_wei = P2 ^ 7;// 定义位引脚

unsigned char code g_duan_Data[] = {

    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, // 熄灭
    0x00// 自定义

};
/*数码管位表*/
unsigned char code g_wei_Data[] = {
    0xfe, // 1111 1110      b
    0xfd, // 1111 1101      b
    0xfb, // 1111 1011      b
    0xf7, // 1111 0111      b
    0xef, // 1110 1111      b
    0xdf, // 1101 1111      b
    0xbf, // 1011 1111      b
    0x7f// 0111 1111      b
};

/*显示一个段值到数码管上
*参数1,duan 需要显示到哪一个段上0-7
*参数2,val 需要显示什么值0-9
*/
void Show_Duan(char wei, char val)
{

    SEGPORT = 0xff;            // 清断码
    g_wei = 1;               // 打开位选
    SEGPORT = g_wei_Data; // 选择位
    g_wei = 0;               // 关闭位选

    SEGPORT = 0xff;             // 清断码
    g_duan = 1;               // 打开段选
    SEGPORT = g_duan_Data; // 选择段
    g_duan = 0;               // 关闭段选
}
/*数码管扫描函数
*参数1:数码管需要显示的函数
*/

void Seg_Scan(ULONG val)
{
    char i;
    char VAL_arr;
    char count = 0;
    if (val == 0)
    {
      Show_Duan((char)(7), 0);
    }

    while (val != 0)
    {
      VAL_arr = val % 10;
      val = val / 10;
      count++;

      for (i = 0; i < count; i++)
      {
            Delay1ms();
            Show_Duan((char)(7 - i), VAL_arr);
      }
    }
}

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

    _nop_();
    _nop_();
    _nop_();
    i = 551UL;
    while (i)
      i--;
}ioinit.c

#include "ioexit.h"
#include <STC32G.H>
/*
*----------------------------------------------------------------------------------------------
* 函数名称:Io_Init
* 函数功能:IO口配置初始化
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/22 10:01:47
* 作者:t176@qq.com
* 创建时间:2023/03/22 10:01:47
-----------------------------------------------------------------------------------------------
*/
void Io_Init()
{
    EAXFR = 1; // 使能访问 XFR

    CKCON = 0x00; // 设置外部数据总线速度为最快

    WTST = 0x00; // 设置程序代码等待参数,赋值为 0 可将 CPU 执行程序的速度设置为最快

    P0M0 = 0x00; // P0 端口设置为普通 IO 口,不启用其他特殊功能

    P0M1 = 0x00;

    P1M0 = 0x00; // P1-P5 端口同理

    P1M1 = 0x00;

    P2M0 = 0x00;

    P2M1 = 0x00;

    P3M0 = 0x00;

    P3M1 = 0x00;

    P4M0 = 0x00;

    P4M1 = 0x00;

    P5M0 = 0x00;

    P5M1 = 0x00;

    P3IM0 = 0x00;

    P3IM1 = 0xFF; // 设置 P3 端口为低电平触发中断

    P3INTE = 0x20; // 使能 P3 口中断(0010 0000 b)

    EA = 1; // 使能总中断
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:Io_Break_Fun
* 函数功能:中断函数
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/22 10:19:51
* 作者:t176@qq.com
* 创建时间:2023/03/22 10:19:51
-----------------------------------------------------------------------------------------------
*/
void Io_Break_Fun() interrupt 40
{ // 中断号为40,可查询手册STC32G 311页

    g_num++;
}main.c

#include "config.h"
#include "display.h"
#include "ioexit.h"

ULONG g_num=0;


void main()

{

    // 采用框架式编程
    //1.定义数据
    //2.系统初始化数据
    Sys_Init(); // 初始化
    while (1)
    {
      // 3.系统数据绘制
      Sys_Draw();
      // ----------------------------------------4.数据更新
      // 4.1用户干预更新数据
      User_Updata();
      // 4.2 系统自动更新数据
      Sys_Updata();
    }
}
// 系统式编程框架-----------------------------------------------

/*框架初始化函数*/
void Sys_Init()
{
/*--初始化IO口参数--*/Io_Init();
}
/*绘制处理数据*/
void Sys_Draw()

{
    Seg_Scan(g_num);

}

/*用户干预更新数据*/
void User_Updata()
{

}
/*系统更新数据*/
void Sys_Updata()
{
}
// 下面数用户函数实现区域-----------------------------------


第17,18集

ADC 就是数值量和模拟量的转换
冲哥在视频中使用一个B站的动画,进行了非常有趣的 演示.
在传统STC89系列,是需要借用外围芯片进行这个步骤的,比如XPT2046
在32G系列中集成了12位高速AD转换器,真的是很强大.

ADC 这个知识本来属于单片机的 中高级应用,掌握这个知识点.就可以调用大量的模块.非常重要的知识.
一下子学不懂的话,就要慢慢的把这个知识点啃下来




第19集

这个是对之前ADC知识点的一个实践.巩固之前的学习,最好还是做下这个试验.加深理解




串口作为单片机与外界设备通信的重要手段 这张是非常重要的
在32G中,串口的使用比STC89系列稍微复杂点
在官方PDF中有相关的列子,可以提供学习,虽然写的很精简.但是学习足够了
一下是二份写的代码
代码1:

main.c

// 编译前,请务必阅读   README.md
#include "config.h"
#include "uart.h"
/*
*----------------------------------------------------------------------------------------------
* 函数名称:main()
* 函数功能:单片机编程框架
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:01:57
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:01:57
* 框架说明:
                执行流程:
                              1.数据定义
                              (执行1次)
                              ---------------------

                              2.Sys_Init()
                              (执行1次)
                              ---------------------

                              3,4,5
                              (循环执行)
                              3.Sys_Draw()数据绘制
                              4.User_Updata()用户干预更新数据
                              5.Sys_Updata()系统自动更新数据

-----------------------------------------------------------------------------------------------
*/
//1.定义数据

void main()

{

      Sys_Init(); // 初始化
      while (1)
      {

                Sys_Draw();
                User_Updata();
                Sys_Updata();
      }
}
// 系统式编程框架-----------------------------------------------

/*
*----------------------------------------------------------------------------------------------
* 函数名称:Sys_Init()
* 函数功能:通常用于初始化一些参数
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:07:24
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:07:24
-----------------------------------------------------------------------------------------------
*/
void Sys_Init()
{
      EAXFR = 1;          // 使能访问 XFR
      CKCON = 0x00; // 设置外部数据总线速度为最快
      WTST = 0x00;// 设置程序代码等待参数,
                                  // 赋值为 0 可将 CPU 执行程序的速度设置为最快
      /*IO口初始化*/
      P0M0 = 0x00;
      P0M1 = 0x00;
      P1M0 = 0x00;
      P1M1 = 0x00;
      P2M0 = 0x00;
      P2M1 = 0x00;
      P3M0 = 0x00;
      P3M1 = 0x00;
      P4M0 = 0x00;
      P4M1 = 0x00;
      P5M0 = 0x00;
      P5M1 = 0x00;
      UartInit();
      ES = 1;
      EA = 1;
      UartSendStr("Use uart1 \r\n");
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:Sys_Draw()
* 函数功能:数据显示,比如数码管,LED灯,TFT 用于数据展示
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:08:05
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:08:05
-----------------------------------------------------------------------------------------------
*/
void Sys_Draw()

{
      UartRev();
      

}

/*
*----------------------------------------------------------------------------------------------
* 函数名称:User_Updata()
* 函数功能:在程序运行中,通常有很多用户需要干预的过程,比如键盘输入
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:09:12
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:09:12
-----------------------------------------------------------------------------------------------
*/
void User_Updata()
{
}

/*
*----------------------------------------------------------------------------------------------
* 函数名称: Sys_Updata()
* 函数功能:通常用于系统自动维护执行的数据(无需用户干预)
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:10:37
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:10:37
-----------------------------------------------------------------------------------------------
*/
void Sys_Updata()
{
}
/*----------------用户自定义的函数----------------*/


uart.c
#include "uart.h"

bit g_busy;
char g_wptr;//写指针(即下一个要写入缓冲区的位置)
char g_rptr;//读指针(即下一个要读取缓冲区中数据的位置)
char g_buffer;//缓冲区。在串口接收中断中,当接收到数据时,将其存储在缓冲区中,并更新写指针

/*
*----------------------------------------------------------------------------------------------
* 函数名称:UartInit()
* 函数功能:串口1初始化
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 09:39:01
* 作者:t176#qq.com
* 创建时间:2023/03/26 09:39:01
-----------------------------------------------------------------------------------------------
*/
void UartInit()
{
    SCON = 0x50;
    T2L = BRT;
    T2H = BRT >> 8;
    S1BRT = 1;
    T2x12 = 1;
    T2R = 1;
    g_wptr = 0x00;
    g_rptr = 0x00;
    g_busy = 0;
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:UartIsr() interrupt 4
* 函数功能:串口中断
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 09:56:19
* 作者:t176#qq.com
* 创建时间:2023/03/26 09:56:19
-----------------------------------------------------------------------------------------------
*/
void UartIsr() interrupt 4
{
    if (TI)
    {
      TI = 0;
      g_busy = 0;
    }
    if (RI)
    {
      RI = 0;
      g_buffer = SBUF;
      g_wptr &= 0x0f;
    }
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称: UartSend(char dat)
* 函数功能:发送一个字节
* 入口参数:@dat:需要发送的字节
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 09:57:08
* 作者:t176#qq.com
* 创建时间:2023/03/26 09:57:08
-----------------------------------------------------------------------------------------------
*/
void UartSend(char dat)
{
    while (g_busy)
      ;
    g_busy = 1;
    SBUF = dat;
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:void UartSendStr(char *p)
* 函数功能:发送字符串
* 入口参数:@p 字符串的指针
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 09:57:47
* 作者:t176#qq.com
* 创建时间:2023/03/26 09:57:47
-----------------------------------------------------------------------------------------------
*/
void UartSendStr(char *p)
{
    while (*p)
    {
      UartSend(*p++);
    }
}

/*
*----------------------------------------------------------------------------------------------
* 函数名称:void UartRev()
* 函数功能:串口接收数据
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 10:00:29
* 作者:t176#qq.com
* 创建时间:2023/03/26 10:00:29
-----------------------------------------------------------------------------------------------
*/
void UartRev()
{
    if (g_rptr != g_wptr)
    {
      UartSend(g_buffer);
      g_rptr &= 0x0f;
    }
}


config.h
/*
*----------------------------------------------------------------------------------------------
* 作者:t176
* 邮箱:t176#qq.com
* 说明:config.h头文件
* 备注:单片机专用框架
       :null
* 当前版本: Ver1.0
* 最后维护时间:2023/03/25 21:59:39
*----------------------------------------------------------------------------------------------
*/



#ifndef __CONFIG_H__
#define __CONFIG_H__
#include <STC32G.H>


#define OPEN_VSCODE_DEBUG //注释该行,将不进入VSCODE调试,为了VSCODE代码编写兼容keil,在烧录前务必注释该行
#ifdef OPEN_VSCODE_DEBUG
#include "../debug/debug.h"
#endif



/*--------------宏定义--------------*/
#define ULONG unsigned long/*无符号整数类型(宏定义)*/


/*--------------变量定义--------------*/



/*--------------函数声明--------------*/

void Sys_Init();
void Sys_Draw();
void User_Updata();
void Sys_Updata();


#endif

uart.h

/*
*----------------------------------------------------------------------------------------------
* 作者:t176
* 邮箱:t176#qq.com
* 说明:uart.h头文件
* 备注:
       :null
* 当前版本: Ver1.0
* 最后维护时间:2023/03/26 09:22:33
*----------------------------------------------------------------------------------------------
*/

#ifndef __UART_H__
#define __UART_H__
#include "config.h"

/*--------------宏定义--------------*/
#define FOSC 11059200UL                     // 定义为无符号长整型,避免计算溢出
#define BRT (65536 - (FOSC / 115200 + 2) / 4) // 加 2 操作是为了让 Keil 编译

/*--------------变量定义--------------*/



/*--------------函数声明--------------*/
void UartRev();
void UartSendStr(char *p);
void UartSend(char dat);
void UartInit();

#endif

README.md


# 整体语言代码结构
!(https://img.shields.io/badge/%E8%8B%B1%E6%96%87-English-blue)
![简体中文 badge](https://img.shields.io/badge/%E7 ... fied%20Chinese-blue)


------------



## 编程语言
###      C语言         (The C Programming Language)
------------


## 硬件环境
### STC降龙棍

------------



## 编译环境

### Keil uVision5 C251

------------


# 代码维护环境
### Visual Studio Code

------------
# 框架式编程
这是框架式编程?

这是一种从整个软件系统的高层次全局视角观察和理解代码的方式。通过代码的上帝视角,开发者可以深入了解软件系统的整体架构、各个部分之间的关系,以及整个系统所解决的问题。这种视角需要开发者具备丰富的知识和经验,熟练掌握各种设计模式和架构模式,并能够在全局范围内做出有利于系统演化和扩展性的设计决策。通过代码的上帝视角,开发者能够更好地理解和优化整个系统,从而提高软件质量和开发效率。


## 框架说明:
                执行流程:
                              1.数据定义
                              (执行1次)
                              ---------------------

                              2.Sys_Init()
                              (执行1次)
                              ---------------------

                              3,4,5
                              (循环执行)
                              3.Sys_Draw()数据绘制
                              4.User_Updata()用户干预更新数据
                              5.Sys_Updata()系统自动更新数据


------------


# 代码风格约定
<font color="#dd00dd">**本代码严格遵循微软代码风格约定</font>
```c
局部变量:   小写可(加下划线)
    float sum = 0.0f;
    float sum_count = 0;


全局变量:g_开头加小驼峰(可加下划线)
    int g_maxStudents = 100;
    float g_averageScore = 0.0f;


函数:    大驼峰(可加下划线)
int CalculateSum(int x, int y);
int Calculate_Sum(int x, int y);


宏定义:全大写
#define PI 3.14159265358979323846
```

------------


# 关于Visual Studio Code调试维护说明
由于keil C251 和VSCode 2个环境的不兼容性,比如使用bit sfr bdata interrupt 时,语法高亮将会失效,为了解决这个问题

特别编写了一个debug.h的头文件来兼容维护环境,以保持VSCode下的语法高亮显示.

需要注意的是,在keil编译时一定注释掉OPEN_VSCODE_DEBUG宏定义,否则编译将会报错

## config.h
<font color="#dd00dd">如果在维护环境下请放开,在keil环境中编译时必须注释该行</font>
####define OPEN_VSCODE_DEBUG ,在编译环境中请注释这行
```c
#define OPEN_VSCODE_DEBUG //注释该行,将不进入VSCODE调试,为了VSCODE代码编写兼容keil,在烧录前务必注释该行
#ifdef OPEN_VSCODE_DEBUG
#include "../debug/debug.h"
#endif

```

## License

作者:t176
------------
MCU_STC License


代码2:
config.h
/*
*----------------------------------------------------------------------------------------------
* 作者:t176
* 邮箱:t176#qq.com
* 说明:config.h头文件
* 备注:单片机专用框架
       :null
* 当前版本: Ver1.0
* 最后维护时间:2023/03/25 21:59:39
*----------------------------------------------------------------------------------------------
*/

#ifndef __CONFIG_H__
#define __CONFIG_H__
#include <STC32G.H>

// #define OPEN_VSCODE_DEBUG //注释该行,将不进入VSCODE调试,为了VSCODE代码编写兼容keil,在烧录前务必注释该行
#ifdef OPEN_VSCODE_DEBUG
#include "../debug/debug.h"
#endif

/*--------------宏定义--------------*/
#define ULONG unsigned long /*无符号整数类型(宏定义)*/

/*--------------变量定义--------------*/

sbit JR6001_BUSY = P3 ^ 5;

/*--------------函数声明--------------*/

void Sys_Init();
void Sys_Draw();
void User_Updata();
void Sys_Updata();

#endif

jr6001.h
/*
*----------------------------------------------------------------------------------------------
* 作者:t176
* 邮箱:t176#qq.com
* 说明:jr6001.c头文件
* 备注:语音模块
       :./ZH/

            02.mp3 2
            03.mp3 3
            04.mp3 4
            05.mp3 5
            06.mp3 6
            07.mp3 7
            08.mp3 8
            09.mp3 9
            10.mp3 0

            19.mp3 个
            11.mp3 十
            12.mp3 百
            13.mp3 千
            14.mp3 万
            15.mp3 点
            16.mp3 首
            17.mp3 元
            18.mp3 亿


            20.mp3 错误
            21.mp3 警告
            22.mp3 任务已完成
            23.mp3 系统启动完成
      ./
            00001.mp3 播放上一曲
            00002.mp3 播放下一曲
            00003.mp3 继续
            00004.mp3 暂停

* 当前版本: Ver1.0
* 最后维护时间:2023/03/30 18:29:49
*----------------------------------------------------------------------------------------------
*/






#ifndef __JR6001_H__
#define __JR6001_H__
#include "uart.h" //包含串口库
#include "STC32G.H"


/*--------------宏定义--------------*/



/*--------------变量定义--------------*/



/*--------------函数声明--------------*/

void Jr6001_Init();
void Play_Upper();
void Play_Next();
void Play_Pause();
void Play_Continue();
void Play_Assemble(char *p);
void Delay100us();
void Delay2000ms();


#endif

keys.h
/*
*----------------------------------------------------------------------------------------------
* 作者:t176
* 邮箱:t176#qq.com
* 说明:keys.h头文件
* 备注:独立键盘P32-P34
       :null
* 当前版本: Ver1.0
* 最后维护时间:2023/04/01 09:31:09
*----------------------------------------------------------------------------------------------
*/






#ifndef __KEYS_H__
#define __KEYS_H__



/*--------------宏定义--------------*/



/*--------------变量定义--------------*/




/*--------------函数声明--------------*/

void Key_Init();
void Key_Scan();


#endif

uart.h
/*
*----------------------------------------------------------------------------------------------
* 作者:t176
* 邮箱:t176#qq.com
* 说明:uart.h头文件
* 备注:
       :null
* 当前版本: Ver1.0
* 最后维护时间:2023/03/26 09:22:33
*----------------------------------------------------------------------------------------------
*/

#ifndef __UART_H__
#define __UART_H__
#include "config.h"

/*--------------宏定义--------------*/
#define FOSC 11059200UL                     // 定义为无符号长整型,避免计算溢出
#define BRT (65536 - (FOSC / 115200 + 2) / 4) // 加 2 操作是为了让 Keil 编译

/*--------------变量定义--------------*/



/*--------------函数声明--------------*/


void UartRev();
void UartSendStr(char *p);
void UartSend(char dat);
void UartInit();

#endif







jr6001.c
#include "jr6001.h"

/*
*----------------------------------------------------------------------------------------------
* 函数名称:Jr6001_int()
* 函数功能: 语音库初始化(23),RXD_2/P3.6, TXD_2/P3.7
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/30 18:36:15
* 作者:t176#qq.com
* 创建时间:2023/03/30 18:36:15
-----------------------------------------------------------------------------------------------
*/
void Jr6001_Init()
{




    char cmd_val[] = "B7:23";
    S1_S1 = 0;
    S1_S0 = 1; // 设置串口引脚 //RXD_2/P3.6, TXD_2/P3.7


    Delay2000ms();
    while (JR6001_BUSY)
    {
      Delay100us();
    }
    Play_Assemble(cmd_val);
    while (JR6001_BUSY)
    {
      Delay100us();
    }
}

/*
*----------------------------------------------------------------------------------------------
* 函数名称:void Play_Upper(){

}
* 函数功能:播放上一曲(00001)
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/30 19:26:37
* 作者:t176#qq.com
* 创建时间:2023/03/30 19:26:37
-----------------------------------------------------------------------------------------------
*/
void Play_Upper()
{
    char cmd_msg[]="A7:00001";
    char cmd_val[] = "A5";


    Play_Assemble(cmd_msg);
    Delay2000ms();
    while (JR6001_BUSY)
    {
      Delay100us();
    }
    Play_Assemble(cmd_val);
    while (JR6001_BUSY)
    {
      Delay100us();
    }
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:Play_next
* 函数功能:播放下一曲(00002)
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/30 19:21:28
* 作者:t176#qq.com
* 创建时间:2023/03/30 19:21:28
-----------------------------------------------------------------------------------------------
*/
void Play_Next()
{

    char cmd_msg[]="A7:00002";
    char cmd_val[] = "A6";


    Play_Assemble(cmd_msg);
    Delay2000ms();
    while (JR6001_BUSY)
    {
      Delay100us();
    }
    Play_Assemble(cmd_val);
    while (JR6001_BUSY)
    {
      Delay100us();
    }
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:Play_Pause()
* 函数功能:暂停播放(00004)
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/30 19:23:59
* 作者:t176#qq.com
* 创建时间:2023/03/30 19:23:59
-----------------------------------------------------------------------------------------------
*/
void Play_Pause()
{
    char cmd_msg[]="A7:00004";
    char cmd_val[] = "A3";


    Play_Assemble(cmd_msg);
    Delay2000ms();
    while (JR6001_BUSY)
    {
      Delay100us();
    }
    Play_Assemble(cmd_val);
    while (JR6001_BUSY)
    {
      Delay100us();
    }
}

/*
*----------------------------------------------------------------------------------------------
* 函数名称:void Play_Continue()
* 函数功能:继续播放(00003)
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/30 19:25:23
* 作者:t176#qq.com
* 创建时间:2023/03/30 19:25:23
-----------------------------------------------------------------------------------------------
*/
void Play_Continue()
{
    char cmd_msg[]="A7:00003";
    char cmd_val[] = "A2";


    Play_Assemble(cmd_msg);
    Delay2000ms();
    while (JR6001_BUSY)
    {
      Delay100us();
    }
    Play_Assemble(cmd_val);
    while (JR6001_BUSY)
    {
      Delay100us();
    }
}

/*
*----------------------------------------------------------------------------------------------
* 函数名称:void Play_Assemble()
* 函数功能:组合播放模式
* 入口参数:val_ptr字符串指针
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/30 19:30:09
* 作者:t176#qq.com
* 创建时间:2023/03/30 19:30:09
-----------------------------------------------------------------------------------------------
*/
void Play_Assemble(char *val_ptr)
{
    UartSendStr(val_ptr);
}

void Delay100us() //@11.0592MHz
{
    unsigned char i;

    _nop_();
    i = 43;
    while (--i)
      ;
}
void Delay2000ms() //@11.0592MHz
{
    unsigned char i, j, k;

    _nop_();
    i = 15;
    j = 2;
    k = 235;
    do
    {
      do
      {
            while (--k)
                ;
      } while (--j);
    } while (--i);
}


keys.c
#include "keys.h"
#include "jr6001.h"

sbit S2 = P3 ^ 2;
sbit S3 = P3 ^ 3;
sbit S4 = P3 ^ 4;

/*
*----------------------------------------------------------------------------------------------
* 函数名称:void Key_Init()
* 函数功能:键盘初始化
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/04/01 09:33:07
* 作者:t176#qq.com
* 创建时间:2023/04/01 09:33:07
-----------------------------------------------------------------------------------------------
*/
void Key_Init()
{
    S2 = 1;
    S3 = 1;
    S4 = 1;
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:void Key_Scan()
* 函数功能:键盘扫描
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/04/01 09:36:43
* 作者:t176#qq.com
* 创建时间:2023/04/01 09:36:43
-----------------------------------------------------------------------------------------------
*/
void Key_Scan()
{
    if (S2 == 0) // 扫描S2
    {
      while (S2 == 0)
            ;
      Play_Upper();
      S2 = 1;
    }
    if (S3 == 0) // 扫描S3
    {
      while (S3 == 0)
            ;
      Play_Next();
      S3 = 1;
    }
    if (S4 == 0) // 扫描S4
    {
      while (S4 == 0)
            ;
       Play_Pause();
      S4 = 1;
    }
}

main.c

// 编译前,请务必阅读   README.md
#include "config.h"
#include "uart.h"
#include "jr6001.h"
#include "keys.h"
/*
*----------------------------------------------------------------------------------------------
* 函数名称:main()
* 函数功能:单片机编程框架
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:01:57
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:01:57
* 框架说明:
                执行流程:
                              1.数据定义
                              (执行1次)
                              ---------------------

                              2.Sys_Init()
                              (执行1次)
                              ---------------------

                              3,4,5
                              (循环执行)
                              3.Sys_Draw()数据绘制
                              4.User_Updata()用户干预更新数据
                              5.Sys_Updata()系统自动更新数据

-----------------------------------------------------------------------------------------------
*/
//1.定义数据

void main()

{

      Sys_Init(); // 初始化
      while (1)
      {

                Sys_Draw();
                User_Updata();
                Sys_Updata();
      }
}
// 系统式编程框架-----------------------------------------------

/*
*----------------------------------------------------------------------------------------------
* 函数名称:Sys_Init()
* 函数功能:通常用于初始化一些参数
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:07:24
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:07:24
-----------------------------------------------------------------------------------------------
*/
void Sys_Init()
{
      EAXFR = 1;          // 使能访问 XFR
      CKCON = 0x00; // 设置外部数据总线速度为最快
      WTST = 0x00;// 设置程序代码等待参数,
                                  // 赋值为 0 可将 CPU 执行程序的速度设置为最快
      /*IO口初始化*/
      P0M0 = 0x00;
      P0M1 = 0x00;
      P1M0 = 0x00;
      P1M1 = 0x00;
      P2M0 = 0x00;
      P2M1 = 0x00;
      P3M0 = 0x00;
      P3M1 = 0x00;
      P4M0 = 0x00;
      P4M1 = 0x00;
      P5M0 = 0x00;
      P5M1 = 0x00;
      UartInit();

      ES = 1;
      EA = 1;
      //UartSendStr("Use uart1 \r\n");
      Jr6001_Init();

}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:Sys_Draw()
* 函数功能:数据显示,比如数码管,LED灯,TFT 用于数据展示
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:08:05
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:08:05
-----------------------------------------------------------------------------------------------
*/
void Sys_Draw()

{
      //   UartRev();      

}

/*
*----------------------------------------------------------------------------------------------
* 函数名称:User_Updata()
* 函数功能:在程序运行中,通常有很多用户需要干预的过程,比如键盘输入
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:09:12
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:09:12
-----------------------------------------------------------------------------------------------
*/
void User_Updata()
{
      Key_Scan();

}

/*
*----------------------------------------------------------------------------------------------
* 函数名称: Sys_Updata()
* 函数功能:通常用于系统自动维护执行的数据(无需用户干预)
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/25 22:10:37
* 作者:t176#qq.com
* 创建时间:2023/03/25 22:10:37
-----------------------------------------------------------------------------------------------
*/
void Sys_Updata()
{
}
/*----------------用户自定义的函数----------------*/


uart.c
#include "uart.h"

bit g_busy;
char g_wptr;//写指针(即下一个要写入缓冲区的位置)
char g_rptr;//读指针(即下一个要读取缓冲区中数据的位置)
char g_buffer;//缓冲区。在串口接收中断中,当接收到数据时,将其存储在缓冲区中,并更新写指针

/*
*----------------------------------------------------------------------------------------------
* 函数名称:UartInit()
* 函数功能:串口1初始化
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 09:39:01
* 作者:t176#qq.com
* 创建时间:2023/03/26 09:39:01
-----------------------------------------------------------------------------------------------
*/
void UartInit()
{
      SCON = 0x50;                //8位数据,可变波特率
      AUXR |= 0x40;                //定时器时钟1T模式
      AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
      TMOD &= 0x0F;                //设置定时器模式
      TL1 = 0xE0;                        //设置定时初始值
      TH1 = 0xFE;                        //设置定时初始值
      ET1 = 0;                        //禁止定时器中断
      TR1 = 1;                        //定时器1开始计时

    g_wptr = 0x00;
    g_rptr = 0x00;
    g_busy = 0;
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:UartIsr() interrupt 4
* 函数功能:串口中断
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 09:56:19
* 作者:t176#qq.com
* 创建时间:2023/03/26 09:56:19
-----------------------------------------------------------------------------------------------
*/
void UartIsr() interrupt 4
{
    if (TI)
    {
      TI = 0;
      g_busy = 0;
    }
    if (RI)
    {
      RI = 0;
      g_buffer = SBUF;
      g_wptr &= 0x0f;
    }
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称: UartSend(char dat)
* 函数功能:发送一个字节
* 入口参数:@dat:需要发送的字节
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 09:57:08
* 作者:t176#qq.com
* 创建时间:2023/03/26 09:57:08
-----------------------------------------------------------------------------------------------
*/
void UartSend(char dat)
{
    while (g_busy);
    g_busy = 1;
    SBUF = dat;
}
/*
*----------------------------------------------------------------------------------------------
* 函数名称:void UartSendStr(char *p)
* 函数功能:发送字符串
* 入口参数:@p 字符串的指针
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 09:57:47
* 作者:t176#qq.com
* 创建时间:2023/03/26 09:57:47
-----------------------------------------------------------------------------------------------
*/
void UartSendStr(char *p)
{
    while (*p)
    {
      UartSend(*p++);
    }
}

/*
*----------------------------------------------------------------------------------------------
* 函数名称:void UartRev()
* 函数功能:串口接收数据
* 入口参数:@
* 函数返回:@
* 当前版本: Ver1.0
* 修改时间:2023/03/26 10:00:29
* 作者:t176#qq.com
* 创建时间:2023/03/26 10:00:29
-----------------------------------------------------------------------------------------------
*/
void UartRev()
{
    if (g_rptr != g_wptr)
    {
      // UartSend(g_buffer);
      UartSend(SBUF);
      
      g_rptr &= 0x0f;
    }
}



CDC 作为一个STC原创技术,相比传统的串口通讯更加具有传输速度快,安全不掉包,和自动缓存机制.由于使用静态库 学习起来比较难.但是我看论坛大佬用它能做很多优秀的demo安装冲哥的说法 虽然这是闭源的代码,但是在试验箱中有相关的代码原型影子,这个需要时间去解读.分析


t176 发表于 2023-4-10 20:35:17

本帖最后由 t176 于 2023-4-11 09:19 编辑

作业:

第六课:

屠龙刀
attach://7509.mp4
降龙棍
attach://7508.mp4

第7课:
屠龙刀
attach://7511.mp4
降龙棍
attach://7513.mp4


第8课:

屠龙刀
attach://7539.mp4

降龙棍

attach://7536.mp4

PS:特殊因素,后面不再上传演示视频.



t176 发表于 2023-4-10 21:59:15

疑问专用楼位:
暂无疑问

电子DIY小家 发表于 2023-4-17 10:23:45

哇,我这入门视频大佬你看是不是有点不习惯{:handshake:}还是感谢支持

t176 发表于 2023-4-17 11:24:01

电子DIY小家 发表于 2023-4-17 10:23
哇,我这入门视频大佬你看是不是有点不习惯还是感谢支持

冲哥 ,你的视频很好,
我刚开始 按照你的视频全给敲一遍代码了.
结果回头发现存源码的U盘丢了.{:dizzy:}
由于是学习代码.当初也没太留意.所以git代码托管 没提交存根.所以就回来补了代码.后面几集的代码因为是重写的,和你的作业要求稍有偏差.见谅
你的教程技术面很全.我后期会要不断的反复学习.
非常感谢你的教程,
页: [1]
查看完整版本: 冲哥STC32G____学习心得