STC32G冲哥视频学习笔记----已完成到第十九集(包含所有完成代码)申请的试验箱到啦
本帖最后由 养只小猫咪 于 2023-5-9 11:03 编辑使用的板子是STC-降龙棍系列核心实验板,原理图如下
https://www.stcaimcu.com/data/attachment/forum/202304/19/100022t55jiq1865o0ofzi.png
环境搭建过程不做记录(安装次数太多了,跟着视频或者找个博客装就OK的)
一、先点个灯
(1)新建工程,然后编写如下代码
https://www.stcaimcu.com/data/attachment/forum/202304/19/100022h0h0tv8i05t5vsda.png
手册上关于GPIO端口配置寄存器中,对于实验P10引脚有效的就只有P1M0寄存器中的P10M0位和P1M1寄存器中的P10M1位
https://www.stcaimcu.com/data/attachment/forum/202304/19/100022vj6i8j86i8wkt64x.png
那根据配置可使用对该位进行清0操作,或者置1操作实现引脚配置
P10配置为准双向IO
https://www.stcaimcu.com/data/attachment/forum/202304/19/100022rmdejm7e77ijb0j8.png
P10配置为推挽输出
https://www.stcaimcu.com/data/attachment/forum/202304/19/100022yblfek6uukbffnbf.png
同理,实验使用P11引脚控制LED灯程序如下,使用推挽模式:
https://www.stcaimcu.com/data/attachment/forum/202304/19/100022phw41571m8u3oujj.png
二、配置HID_不断电下载
获取需要文件文件
https://www.stcaimcu.com/data/attachment/forum/202304/19/132809oxmltcko0za1zuhz.png
(1)hid的库
https://www.stcaimcu.com/data/attachment/forum/202304/19/132809fbifut6buqzm4tbf.png
(2)其他的头文件
https://www.stcaimcu.com/data/attachment/forum/202304/19/132809kxx6gsssgsg899dg.png
2、根据视频进行代码编写
https://www.stcaimcu.com/data/attachment/forum/202304/19/132809uuuls0nqvatue00a.png
3、按照教程对STC-ISP进行设置(我用的是6.91N版本)
https://www.stcaimcu.com/data/attachment/forum/202304/19/132809r2d2egpbppzpk1qb.png
编译可能会出现 57号警告
https://www.stcaimcu.com/data/attachment/forum/202304/19/132809wk26xwtqz2tkm67t.png
解决方式:
https://www.stcaimcu.com/data/attachment/forum/202304/19/132809f5osdsstotvbhtbv.png
忽略该警告
4、然后下载,一切正常
三、USB-CDC虚拟串口,不停电下载
1、CDC库的获取
https://www.stcaimcu.com/data/attachment/forum/202304/19/134644v3jp754013u3xju1.png
2、STC-ISP软件的配置
检查一下STC-CDC/USB转串口的驱动是否安装!!!!!!
如果安装正常在电脑的设备管理器 端口下面会有这样的显示
如果跟上述图片显示不一样
打开STC-ISP进行安装
3、根据视频添加库,修改代码
https://www.stcaimcu.com/data/attachment/forum/202304/19/134644u6o8qqi6q2xo8zzm.png
4、进行程序下载验证
四、USB-CDC虚拟串口,使用printf函数
1、对照视频进行程序编写,只是与上个例程之间差了几行代码
程序编译下载之后,打开STC-ISP的串口助手进行验证
五、printf格式、进制转换基础、C语言常用运算符以及数据的基本类型
1、printf格式输出
2、进制转换基础
3、c语言常用运算符
4、数据类型
程序附件只放第二个例程个第四个例程,有兴趣的可以下载看看!!
本帖最后由 养只小猫咪 于 2023-4-20 09:20 编辑
七、按键点灯
使用的是P0口的8个引脚控制LED灯,使用P32和P33作为按键,实现分别实现
按下点亮,松开熄灭、
按下熄灭,松开点亮、
按下一次,状态取反,按键松开才执行
按下一次,状态取反,按键按下就执行
KEY1按下一,灯左移一个单位,KEY2按下,灯右移一个单位
数组流水灯
具体代码见附件程序
八、蜂鸣器应用
主要实现功能是:
/*
按键1按下,蜂鸣器响10ms,LED1-8全部电亮200ms后熄灭,表示开机
开机后,按键2按下,蜂鸣器响10ms,LED1-8轮流点亮
按键1再次按下,蜂鸣器响10ms,LED1-8全部熄灭,表示关机
增加按键3,按下按键3之后表示启动,选择的对应功能的LED灯持续闪烁,表示正在工作,且在工作时无法进行功能切换
*/
主要的功能代码:
u8 State_Flag = 0; /* 表示开关机状态0 表示关机,1表示开机 */
u8 Run_Flag = 0; /* 表示运行状态0 表示没开始运行,1表示开始运行 */
u8 Run_Mode = 0 ; /* 0-8 模式选择0:无模式 */
/*
按键1按下,蜂鸣器响10ms,LED1-8全部电亮200ms后熄灭,表示开机
开机后,按键2按下,蜂鸣器响10ms,LED1-8轮流点亮
按键1再次按下,蜂鸣器响10ms,LED1-8全部熄灭,表示关机
增加按键3,按下按键3之后表示启动,选择的对应功能的LED灯持续闪烁,表示正在工作,且在工作时无法进行功能切换
*/
void test(void)
{
if(KEY1 == 0)
{
delay_ms(10);
if(KEY1 == 0)/* 按键1被按下 */
{
switch(State_Flag)
{
case 0:
BEEP = 1;
delay_ms(10);
BEEP = 0;
LED = 0x00 ;
delay_ms(200);
LED = 0xFF ;
State_Flag = 1;
break;
case 1:
BEEP = 1;
delay_ms(10);
BEEP = 0;
LED = 0xFF ;
State_Flag = 0;
Run_Mode = 0; /* 关机后模式清0 */
Run_Flag = 0;
break;
}
while(KEY1 == 0);/*先执行,按键在松开 */
}
}
if(State_Flag && (!Run_Flag))
{
if(KEY2 == 0)
{
delay_ms(10);
if(KEY2 == 0)
{
BEEP = 1;
delay_ms(10);
BEEP = 0;
Run_Mode++;
if(Run_Mode > 8)
Run_Mode = 1;
LED =~(1<<(Run_Mode-1));
while(KEY2 == 0);/* 先执行,按键在松开 */
}
}
}
if(KEY3 == 0)
{
delay_ms(10);
if(KEY3 == 0)
{
if(Run_Mode > 0)
{
Run_Flag = !Run_Flag;
LED =~(1<<(Run_Mode-1));
}
while(KEY3 == 0);/* 先执行,按键在松开 */
}
}
if(Run_Flag)
{
LED =~(1<<(Run_Mode-1));
delay_ms(100);
LED = 0xFF;
delay_ms(100);
}
}
完整工程代码见附件
楼主优秀{:4_250:} 九、数码管静态显示
由于降龙棍系列实验板没有数码管外设,所以后面的学习就更换成手边有的天问51的STC32G开发板,实物图,原理图如下:
后续程序都是基于此板进行,由于该板板载蜂鸣器是无源蜂鸣器,所以前面蜂鸣器部分的操作都由P41控制的一个LED灯进行完成。
由于开发板上的数码管与STC32G之间加了一个74HC595,所以可能与冲哥视频上的一些代码不一样,不过实现功能的代码思路上是一致的
主要代码如下:
使用KEY1和KEY2来对0-9数码管进行加减
u8 SMG_Tab = { 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90 };/* 0-9 */
char num = 0;
void SMG_test(void)
{
if(KEY1 == 0)
{
delay_ms(10);
if(KEY1 == 0)
{
num++;
if(num>9)
{
num = 9;
}
while(KEY1 == 0);
}
}
if(KEY2 == 0)
{
delay_ms(10);
if(KEY2 == 0)
{
num--;
if(num<0)
{
num = 0;
}
while(KEY2 == 0);
}
}
LED = SMG_Tab;
}
使用KEY1、KEY2和KEY3来对0-9数码管进行循环显示,按KEY3会让蜂鸣器响改数字次数的声
u8 SMG_Tab = { 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90 };/* 0-9 */
char num = 0;
void Beep_Di_Num(u8 num)
{
int i;
for(i = num; i>0;i-- )
{
BEEP = 1;
delay_ms(200);
BEEP = 0;
delay_ms(200);
}
}
void SMG_test(void)
{
if(KEY1 == 0)
{
delay_ms(10);
if(KEY1 == 0)
{
num++;
if(num>9)
{
num = 0;
}
while(KEY1 == 0);
}
}
if(KEY2 == 0)
{
delay_ms(10);
if(KEY2 == 0)
{
num--;
if(num<0)
{
num = 9;
}
while(KEY2 == 0);
}
}
if(KEY3 == 0)
{
delay_ms(10);
if(KEY3 == 0)
{
Beep_Di_Num(num);
while(KEY2 == 0);
}
}
LED = SMG_Tab;
}
完整工程代码可通过附件下载
STC爱好者 发表于 2023-4-20 11:35
楼主优秀
{:lol:}相互学习 10、动态数码管显示
共用变量定义:
/********************0 1 2 3 4 5 6 7 8 9 0. 1. 2. 3. 4. 5. 6. 7.8. 9. - ***************************/
u8 SMG_Tab = { 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xBF};/* 0-9 + 0-9带. */
u8 COM_Tab ={ 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};/* 位码 */
u8 Show_Tab = { 0,0,20,0,0,20,0,0 };
u8 num = 0;
u32 Time_Count = 0;
u8 Run_Flag = 0;
u8 hour = 0;/* 时 */
u8 min = 0; /* 分 */
u8 Sec = 0; /* 秒 */
(1)完成了在八个数码管上显0-7的显示,主要功能代码如下
void SMG_test(void)
{
Send_595(COM_Tab) ;/* 位码选择第8位 */
LED = SMG_Tab;/* 段码显示1 */
delay_ms(1);
num++;
if(num>7)
{
num = 0;
}
}
(2)动态显示一个八位数,主要功能代码如下
void SMG_test(void)
{
Send_595(COM_Tab) ;/* 位码选择 */
LED = SMG_Tab];/* 段码显示1 */
delay_ms(1);
num++;
if(num>7)
{
num = 0;
}
}
(3)10秒免单计数器,主要功能代码如下
在前四位数码管显示目标时间,即10.00,表示定时10秒钟
后四位显示当前的计时00.00,最小单位为10ms
按下开始按钮KEY1后,每10ms最末尾的数字加一,再次按下KEY1按钮后停止计时
void SMG_test(void)
{
Show_Tab = 1;
Show_Tab = 10;
Show_Tab = 0;
Show_Tab = 0;
if(Run_Flag)
{
Time_Count++;
Show_Tab = Time_Count/10000%10; /* 取万位 */
Show_Tab = Time_Count/1000%10+10;/* 取千位+小数点 */
Show_Tab = Time_Count/100%10; /* 取百位 */
Show_Tab = Time_Count/10%10; /* 取十位 */
}
Send_595(COM_Tab) ;/* 位码选择 */
LED = SMG_Tab];/* 段码显示1 */
delay_ms(1);
num++;
if(num>7)
{
num = 0;
}
if(KEY1 == 0)
{
delay_ms(10);
if(KEY1 == 0)
{
while(KEY1 == 0)
{
Send_595(COM_Tab) ;/* 位码选择 */
LED = SMG_Tab];/* 段码显示1 */
delay_ms(1);
num++;
if(num>7)
{
num = 0;
}
}
Run_Flag = !Run_Flag;
if(Run_Flag == 0)
{
Time_Count = 0;
}
}
}
}
(4)简易时钟 ,主要功能代码如下
初始状态显示00-00-00,分别表示时、分、秒
每隔1秒钟,秒+1,一分钟,分+1,以此类推
时间到达00-00-30的时候,蜂鸣器响3秒表示闹钟
void SMG_test(void)
{
delay_ms(1);
Time_Count++;
if(Time_Count>=500)/* 不精确秒延时 */
{
Time_Count = 0;
Sec++;
if(Sec>=60)
{
Sec = 0;
min++;
}
}
if(min>=60)
{
min = 0;
hour++;
}
if(hour>=24)
{
hour = 0;
}
Show_Tab = Sec%10;/* 获取秒的个位 */
Show_Tab = Sec/10;/* 获取秒的十位 */
Show_Tab = min%10;/* 获取分的个位 */
Show_Tab = min/10;/* 获取分的十位 */
Show_Tab = hour%10;/* 获取时的个位 */
Show_Tab = hour/10;/* 获取时的十位 */
if((hour == 0) && (min == 0) && (Sec == 30))
{
BEEP = 1;
}
if((hour == 0) && (min == 0) && (Sec == 33))
{
BEEP = 0;
}
Send_595(COM_Tab) ;/* 位码选择 */
LED = SMG_Tab];/* 段码显示1 */
delay_ms(1);
num++;
if(num>7)
{
num = 0;
}
}
完整的工程代码,如附件所示
本帖最后由 养只小猫咪 于 2023-4-20 22:25 编辑
11、定时器
STC32G内部有T0-T4五个定时器且它们都可以工作在定时器模式挥着是计数器模式,这章只讨论其作为定时器使用的功能
如上图所示,T0-T4五个定时器中支持的模式是不同的,四种工作模式如下图所示
由于T1-T4的工作方式都是T0定时器的子集,所以只验证T0定时器的功能,其余的同理
T0定时器
1、设置T0定时器的工作方式,工作在定时器模式下(TMOD)
TMOD &= (0<<2)
2、设置T0定时器的计数脉冲是系统时钟1分频的还是系统时钟的12分频(AUXR)
定时器输入时钟是系统时钟的1分频和12分频有什么区别呢?
当前使用的系统时钟是24MHZ
12分频模式下:
定时器输入时钟是2MHZ,也就是说计数器计一个数是0.5us,如果需要定时器计时1ms,也就是说计数器要加到2000
由于STC32G使用的是16位计数器,最大计数值是65535,所以在12分频的模式下的最大定时时间为0.5us * 65535即32.7675ms
1T模式:
定时器输入时钟是24MHZ,也就是说计数器计一个数是1/24000000秒,如果需要定时器计时1ms,也就是说计数器要加到24000
由于STC32G使用的是16位计数器,最大计数值是65535,所以在1分频的模式下的最大定时时间为1/24000000秒 * 65535即大约是2.73ms
我们一般配置成12分频模式即可
AUXR &= (0<<7)
3、设置定时器工作模式(TMOD)
常用的就是16位自动重装载模式
也就是TMOD &= (0xFC)
4、定时器0控制寄存器配置(TCON)
TMOD &= (0<<3) 将T0_GATE位清0
TR0 = 1 定时器开始运行
5、打开定时器0的中断
ET0 = 1
6、编写定时器0中断函数
定时器的中断号等于0
void Timer0_Isr(void) interrupt 1
{
}
对了,还有定时时间设定后的TH0和TL0的计算
我们设定定时时间1ms,定时器选择12分频,16位自动重载模式则根据计算
(65536-[ TH0,TL0 ]) *12= 24000000 * 0.001 根据计算可得[ TH0,TL0 ] = 2000
TH0 = 0xF8
TL0 = 0x30
总结一下:
void Timer0_Init(void)
{
TMOD &= (0<<2); /* 配置定时器0工作在定时器方式下 */
AUXR &= (0<<7); /* 设置定时器0输入时钟为12分频 */
TMOD &= (0xFC); /* 配置定时器0工作在模式0,16位自动重装载模式下 */
TH0 = 0xF8;
TL0 = 0x30;
TF0 = 0; //清除TF0标志
TMOD &= (0<<3); /* 将T0_GATE位清0 */
TR0 = 1 ; /* 定时器0开始运行 */
ET0 = 1; /* 定时器0中断打开 */
}
/**************************将定时器定时1ms然后修改上个章节的10秒免单计数器的程序*******************************************/
主要程序如下:
void SMG_test(void)
{
Show_Tab = 1;
Show_Tab = 10;
Show_Tab = 0;
Show_Tab = 0;
if(Run_Flag)
{
Show_Tab = Time_Count/10000%10; /* 取万位 */
Show_Tab = Time_Count/1000%10+10;/* 取千位+小数点 */
Show_Tab = Time_Count/100%10; /* 取百位 */
Show_Tab = Time_Count/10%10; /* 取十位 */
}
if(KEY1 == 0)
{
delay_ms(10);
if(KEY1 == 0)
{
while(KEY1 == 0);
Run_Flag = !Run_Flag;
Time_Count = 0;
}
}
}
#if 0 /* 自己推导编写代码 */
void Timer0_Init(void)
{
TMOD &= (0<<2); /* 配置定时器0工作在定时器方式下 */
AUXR &= (0<<7); /* 设置定时器0输入时钟为12分频 */
TMOD &= (0xFC); /* 配置定时器0工作在模式0,16位自动重装载模式下 */
TH0 = 0xF8;
TL0 = 0x30;
TF0 = 0; //清除TF0标志
TMOD &= (0<<3); /* 将T0_GATE位清0 */
TR0 = 1 ; /* 定时器0开始运行 */
ET0 = 1; /* 定时器0中断打开 */
}
#endif
#if 1 /* 定时器计算器生成代码 */
void Timer0_Init(void)
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x30; //设置定时初始值
TH0 = 0xF8; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
#endif
/* 定时器0的中断服务函数 */
void Timer0_ISR(void)interrupt1
{
Time_Count++;
Send_595(COM_Tab) ; /* 位码选择 */
LED = SMG_Tab];/* 段码显示1 */
num++;
if(num>7)
{
num = 0;
}
}
/******************************************************将定时器定时1ms然后修改上个章节的简易时钟程序,并使用KEY1控制其运行和暂停*********************************************************************/
主要代码如下:
void SMG_test(void)
{
if(Time_Count>=1000)/* 精确秒延时 */
{
Time_Count = 0;
Sec++;
if(Sec>=60)
{
Sec = 0;
min++;
}
}
if(min>=60)
{
min = 0;
hour++;
}
if(hour>=24)
{
hour = 0;
}
Show_Tab = Sec%10;/* 获取秒的个位 */
Show_Tab = Sec/10;/* 获取秒的十位 */
Show_Tab = min%10;/* 获取分的个位 */
Show_Tab = min/10;/* 获取分的十位 */
Show_Tab = hour%10;/* 获取时的个位 */
Show_Tab = hour/10;/* 获取时的十位 */
if((hour == 0) && (min == 0) && (Sec == 30))
{
BEEP = 1;
}
if((hour == 0) && (min == 0) && (Sec == 33))
{
BEEP = 0;
}
if(KEY1 == 0)
{
delay_ms(10);
if(KEY1 == 0)
{
Stop_Flag = !Stop_Flag;
while(KEY1 == 0);
}
}
}
/* 定时器计算器生成代码 */
void Timer0_Init(void)
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x30; //设置定时初始值
TH0 = 0xF8; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
/* 定时器0的中断服务函数 */
void Timer0_ISR(void)interrupt1
{
if(Stop_Flag == 0)
{
Time_Count++;
}
Send_595(COM_Tab) ;/* 位码选择 */
LED = SMG_Tab];/* 段码显示1 */
num++;
if(num>7)
{
num = 0;
}
}
以上两个例程的完整工程代码,请下载附件内容观看
最后最后大赞一下STC-ISP的定时器计算器功能
/****************************************************************Warning*******************************************************************/
使用定时器的时候出现了这样一个警告:
最后通过
去掉这个这个 4 Byte interupt Frame Size选项消除了这个警告
十二、计数器的使用
将定时器x配置成计数器还是定时器使用,主要是通过对TMOD寄存器进行配置完成的。.
以定时器0为例:
对于用作定时器或者计数器后他的工作模式,
自动重装载模式和不自动重载模式的区别请移步看我另一个帖子
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=1936
使用T0作为定时器定时1ms,然后每隔1S对T1计数器产生的脉冲数通过数码管进行显示,主要代码如下所示:
void Timer1_Init(void)
{
TMOD = 0x50; //设置定时器模式
TL1 = 0x00; //设置定时初始值
TH1 = 0x00; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
}
void Timer0_Count_Init(void)//1毫秒@24.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x30; //设置定时初始值
TH0 = 0xF8; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
void Timer0_Isr(void) interrupt 1
{
Time_Count++;
if(Time_Count>=1000)/* 转每秒 */
{
Time_Count = 0;
Count_T1 = (TH1*256)+TL1;
TH1 = 0x00;
TL1 = 0x00;
Show_Tab = Count_T1/1000%10;
Show_Tab = Count_T1/100%10;
Show_Tab = Count_T1/10%10;
Show_Tab = Count_T1%10;
}
Send_595(COM_Tab) ; /* 位码选择第8位 */
LED = SMG_Tab] ; /* 段码显示1 */
num++;
if(num>3)
{
num = 0;
}
}
完整的工程代码请下载附件进行观看
STC32G冲哥视频学习笔记--------包含所有代码
《STC32位8051单片机原理及C语言程序设计视频教程》
十三、多文件模块化编程 学习
永远不能停下学习的脚步,之前也有些编程基础,但只是富裕表面,不求甚解。
之前关于多文件模块化多少也是知道的,可是关于局部变量,局部静态变量这些都没什么多大的概念,
基本都是一个全局变量去解决,看完视频之后真的获益良多,
除此之外状态机编程的思想,之前也是接触过的,可一直也没有去深究,搞得现在编程总是不上不下的,
现在沉下心来好好地思考这些,有种豁然开量的感觉,感谢冲哥的视频!!
关于我自己写的代码,还是放在附件中,有兴趣的可以看看。
【新提醒】看32位8051教学视频,送实验箱,200万大奖等你拿 - 开源广场及教学视频交流 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)