冲哥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)

------------
## 编程语言
### 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-11 09:19 编辑
作业:
第六课:
屠龙刀
attach://7509.mp4
降龙棍
attach://7508.mp4
第7课:
屠龙刀
attach://7511.mp4
降龙棍
attach://7513.mp4
第8课:
屠龙刀
attach://7539.mp4
降龙棍
attach://7536.mp4
PS:特殊因素,后面不再上传演示视频.
疑问专用楼位:
暂无疑问 哇,我这入门视频大佬你看是不是有点不习惯{:handshake:}还是感谢支持 电子DIY小家 发表于 2023-4-17 10:23
哇,我这入门视频大佬你看是不是有点不习惯还是感谢支持
冲哥 ,你的视频很好,
我刚开始 按照你的视频全给敲一遍代码了.
结果回头发现存源码的U盘丢了.{:dizzy:}
由于是学习代码.当初也没太留意.所以git代码托管 没提交存根.所以就回来补了代码.后面几集的代码因为是重写的,和你的作业要求稍有偏差.见谅
你的教程技术面很全.我后期会要不断的反复学习.
非常感谢你的教程,
页:
[1]