找回密码
 立即注册
查看: 3924|回复: 30

STC32单片机学习记录 | 建议立即 【免费+包邮送】实验箱,提高学习效率

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-27 22:44:27 | 显示全部楼层 |阅读模式
第四集
点亮第一个LED

输出电压 = VCC为高电平
输出电压 = GND为低电平
单片机可以控制GPIO口输出高低电平
总结:LED的阳极为高电平、阴极为低电平 点亮

sfr是将要写入的地址重命名
如:sfr P0 = 0x80,以后给P0赋值,就相当于往单片机的0x80中写入数据了,如P0 = 0x00;就是向0x80地址写0x00
sbit是将想操作的位寄存器重命名
如:sbit P00 = P0^0; 就是把P0口的0号脚定义为P00,可以单独操作一个引脚(当然P00也可以用其他字符表示,如LED,BEEP...)
P0M0,P0M1是配置我们GPIO的模式的
1.P0M0 = 0x00;P0M1 = 0x00是准双向口模式(我们上电复位默认就是这个模式)
2.P0M0 = 0xff;P0M1 =0x00 是推挽输出模式
3.P0M0 = 0x00;P0M1 =0xff 是高阻输入模式
4. P0M0 = 0xff;P0M1 = 0xff; 是开漏输出模式
具体各个模式的作用大家可以参考数据手册

下面是我参考视频写的代码(由于我没有实验箱,自己买的一块开发板,将LED的正极接P00端口,负极接GND)
/*********************************************************/

sfr P0 = 0x80;
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sbit P00 = P0^0;
void main()
{
        P0M0 = 0xff;        //这里我选择了推挽输出模式,驱动电流大一点,LED会更亮一些,准双向口模式也是可以的
        P0M1 = 0x00;
        while(1)
        {
                //P0= 0x01; //0000 0001 P00口为高电平
                P00 = 1;
               
        }
}
下面两张图片分别是准双向口模式和推挽输出模式下LED灯的亮度
323E3E2C355696F2AFD3894C448D7C2B.jpg 4220ED2D12CB0F0FF4BA6A9C8B4AF30F.jpg



回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-27 23:45:11 | 显示全部楼层

第五集

本帖最后由 Crystalline 于 2023-12-27 23:46 编辑

第五集
C语言运算符和进制转换
本讲主要内容
1.printf函数
2.进制转换
3.运算符
4.数据类型

视频中用到串口打印方法
while(1)
{

        if(DeviceState!=DEVSTATE_CONFIGURED)
                continue;
        if(bUsbOutReady)
        {
                usb_OUT_done(); //接收应答

         printf("Hello world!");
}
这样就能打印在串口上,原理我不懂,有没有大佬解释一下


进制转换就是2进制、8进制、16进制、10进制之间的相互转换了
我来讲一下我理解的进制间的相互转换

二进制转八进制: 将二进制数按每3位一组转换为八进制数。
二进制转十进制: 将每一位的二进制数乘以2的幂并相加。
二进制转十六进制: 将每四位一组的二进制数转换为对应的十六进制数。



八进制转二进制: 将每一位的八进制数转换为对应的3位二进制数。
八进制转十进制: 将每一位的八进制数乘以8的幂并相加。
八进制转十六进制: 先转换为二进制,然后再将二进制转换为十六进制。



十进制转二进制: 可以通过不断地除以2并记录余数的方式得到二进制表示。
十进制转八进制: 可以通过不断地除以8并记录余数的方式得到八进制表示。
十进制转十六进制: 可以通过不断地除以16并记录余数的方式得到十六进制表示。



十六进制转二进制: 将每一位的十六进制数转换为对应的4位二进制数。
十六进制转八进制: 先转换为二进制,然后再将二进制转换为八进制。
十六进制转十进制: 将每一位的十六进制数乘以16的幂并相加。


基本的运算符+ - * / %就没有什么好说的呢,大家可以看看c语言课程
数据类型基本也就会用到 int float char这三种
还有一点就是printf函数的输出格式,printf("%d",变量);
%d可以换成%f、%c,取决于数据类型
%x.yf意思是输出总宽度为x,小数保留y位
大家这样记住就行了
比如一个float类型的变量a = 1.23
printf("%2.1f",a)的结果是1.2
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-28 14:11:43 | 显示全部楼层
本帖最后由 Crystalline 于 2023-12-28 16:01 编辑

第六集
LED闪烁和花式点灯
基本单位的换算
1s = 1000ms  =1000000us[apoyl_multivideo]
按照视频里的方法我发现LED闪烁的时间不是500ms,差不多1s
我开始怀疑是运行频率不对,
我看到stc-isp软件上的提示,去数据手册查了一下WTST寄存器才知道
5]NZ`ND7B9K@}R7%)@VQT15.png PMU8E)EKI380NOJ_AI[G2(A.png

下面把WTST寄存器清零就好了!
sfr P0 = 0x80;
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr WTST=0xE9;
sbit P00 = P0^0;
#define MAIN_Fosc 24000000UL

void delay_ms(unsigned int ms)
{
        unsigned int i;
        do{
                i = MAIN_Fosc/6000;
                while(--i);
        }while(--ms);
}
void main()
{
        WTST = 0x00;
        P0M0 = 0xff;        
        P0M1 = 0x00;
        while(1)
        {
                //P0= 0x01; //0000 0001 P00口为高电平
                P00 = 1;
                delay_ms(500);
                P00 = 0;
                delay_ms(500);
        }
}

VID20231228140342.mp4

6.76 MB, 下载次数: 200

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-28 15:45:44 | 显示全部楼层
本帖最后由 Crystalline 于 2023-12-28 18:22 编辑

第七集
按键点灯
由于没有外接的按键,我也不好实践,我想了一个办法模拟按键,用一根杜邦线的一端接按键的GPIO口,另一端接地或VCC(接地时模拟按键被按下,接VCC时模拟按键悬空)
把按键的GPIO设置为高阻输入模式
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr WTST=0xE9;
sbit LED= P0^0;
sbit KEY = P0^1;
#define MAIN_Fosc 24000000UL
void delay_ms(unsigned int ms)
{
        unsigned int i;
        do{
                i = MAIN_Fosc/6000;
                while(--i);
        }while(--ms);
}
void main()
{
        WTST = 0x00;
    P0M0 = 0xfd; P0M1 = 0x02;


        LED = 0;
        while(1)
        {
                if(KEY == 0)
                {
                        delay_ms(10);
                        if(KEY ==0)
                        LED = 1;
                }
                //else      如果要按住点亮,松开熄灭的话,需要加上这段代码
                 //LED = 0;
        }

}

没有多个LED灯,就只能试一试按键点亮LED了
如果能收到实验箱的话,我再把这部分内容更新一下

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-28 19:20:55 | 显示全部楼层
本帖最后由 Crystalline 于 2023-12-28 19:34 编辑

第八集
蜂鸣器的应用
有源蜂鸣器和无源蜂鸣器的区别:
有源蜂鸣器内部含震荡源,通电就会叫
无源蜂鸣器内部无震荡源,要给一定频率的方波信号才会叫

驱动有源蜂鸣器其实和驱动LED差不多,都是IO口输出高低电平来控制
可以类比LED灯的程序
本讲主要讲的是蜂鸣器的应用:电磁炉
既结合了之前的LED,又结合了本讲的蜂鸣器
1.png

2.png

结合冲哥讲的内容,我自己写了一套代码(没有试验箱,确定不了代码是不是正确的,各位可以帮我看看)



//假设LED是高电平点亮,BEEP是低电平叫,按键接了上拉电阻
sfr P0 = 0x80;
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1 = 0x90;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr WTST=0xE9;

#define MAIN_Fosc 24000000UL
#define LED P0;                //把八个LED接在P0口

sbit KEY1 = P1^0;
sbit KEY2 = P1^2;
sbit KEY3 = P1^3;
sbit BEEP = P1^4;

unsigned char Mode =0 ;
bit flag = 0;//定义开关机状态,初始化关机
bit Working = 0; //定义启动状态,初始化未启动
void delay_ms(unsigned int ms)
{
        unsigned int i;
        do{
                i = MAIN_Fosc/6000;
                while(--i);
        }while(--ms);
}
void System_Init()
{
        WTST = 0x00;
        P0M0 = 0xff;
        P0M1 = 0x00; //配置P0口为推挽输出
       
        P1M0 = 0x00;
        P1M1 = 0xff;//配置P1口为高阻输入
       
        LED = 0x00;        //初始化LED熄灭

}
unsigned char Key_handler()
{
        if(KEY1 == 0)
        {       
                delay_ms(10);
                while(KEY1 ==0);
                return 1;
        }
        else if(KEY2 == 0)
        {
                delay_ms(10);
                while(KEY2 == 0);
                return 2;
        }
        else if(KEY3 == 0)
        {
                delay_ms(10);
                while(KEY3==0);
                return 3;
        }
        return 0;
}
void main()
{
        unsigned char Key_num;
        System_Init();
        while(1)
        {
                Key_num = Key_handler();

                switch(Key_num)
                {
                        case 1:
                        if(flag == 1)
                        {
                                flag = 0;
                                BEEP = 0;delay_ms(10);BEEP = 1;
                                LED = 0x00;
                        }
                        flag = 1; //开机
                        BEEP = 0;delay_ms(10);BEEP = 1;
                        LED = 0xff;delay_ms(200);LED = 0x00;
                        break;
                       
                        case 2:
                        if(flag == 1)
                        {
                               
                                Mode++;
                                if(Mode == 9)Mode =1;
                                BEEP = 0;delay_ms(10);BEEP = 1;
                                LED = 0x01<<Mode-1;
                        }
                        break;
                       
                        case 3:
                                if(Working == 0)
                                {
                                                Working =1;
                                }
                        break;
                }
        }
        if(Working == 1 && Mode!=0)
        {
                LED = 0x01<<Mode-1;
                delay_ms(200);
                LED = 0x00;
                delay_ms(200);
        }
        else
                LED = 0x01<<Mode-1;
}



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-28 20:13:00 | 显示全部楼层
第九集
静态数码管的使用

数码管可以分为共阴和共阳两种,本质上就是多段LED灯
3.png


P67
P66
P65
P64
P63
P62
P61
P60

dp
g
f
e
d
c
b
a
0
1
1
0
0
0
0
0
0
1
1
1
1
1
1
1
0
0
2
1
0
1
0
0
1
0
0
3
1
0
1
1
0
0
0
0
4
1
0
0
1
1
0
0
1
5
1
0
0
1
0
0
1
0
6
1
0
0
0
0
0
1
0
7
1
1
1
1
1
0
0
0
8 1 00 0 0 0 0 0
9 1 0 0 0 1 0 0 0
这是共阳极数码管段码表,共阴极就是按位取反
给要显示的位选口赋1,把上表的二进制数转化成16进制或10进制存放在数组里面,赋值给P6口就可以让数码管显示相应的数字了!




回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-29 13:30:19 | 显示全部楼层
第十集

数码管的动态显示
数码管动态显示的原理就是利用人眼分辨不出50HZ以上的刷新率
4.png
只要让相邻两个数码管亮的间隔为1ms,在我们视角里它就是同时点亮的。
同时点亮八个数码管,逻辑就是:位选——段选——1ms延时——位选....
有一点我不明白,能不能让这个数码管亮的间隔更小呢?1us可以吗?
截图202312291327414480.jpg
后面冲哥又以免单计数器给我们实战演练了一下动态数码管的应用,学一个东西马上就去实践它,好的教学!!!




回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-29 14:50:10 | 显示全部楼层
第十一集

定时器的使用
截图202312291333561591.jpg

截图202312291337092927.jpg

delay函数占用CPU大量时间,利用定时器中断可以定时进中断,提高CPU的运行效率
冲哥举了一个很形象的例子,主程序:你在背书 中断:妈妈让你5min后去看看锅里的汤有没有烧干
而如果不用中断表示的话,那就是 主程序:你在背书,过5min后再去看看锅里的汤有没有烧干
很明显你背书的时间是不确定的,中断可以打断你的背书,5min后立马去看看水有没有烧干,再回来继续背
而如果不用中断,你就要等背完书再去看看水有没有烧干,说不定那个时候水已经烧干了呢?
截图202312291417475185.jpg

截图202312291420052038.jpg

使用定时器0定时要把TMOD中的 截图202312291420561900.jpg 清零,分频与不分频取决于T0x12,计数值相差12倍
截图202312291430178088.jpg 截图202312291430561641.jpg


截图202312291432312085.jpg 截图202312291433228438.jpg

定时时间计算方法:
截图202312291439446847.jpg

截图202312291443263714.jpg

配置定时器0进行1ms定时,定时器0中断号为1,中断处理函数要加上interrupt 1,函数名可以随便起
这样就配置好了1ms的定时器中断
计算定时长度太麻烦的话可以使用stc-isp软件

截图202312291449023624.jpg





回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-30 16:56:52 | 显示全部楼层
本帖最后由 Crystalline 于 2023-12-30 16:57 编辑

感谢STC!实验箱已经在路上了!如此良心!不愧是国产单片机/MCU的领航者,1T 8051单片机的领导者,328051单片机的领导者!
第十二集
计数器的使用
上一节课用的是定时器0作为定时器的模式,这节课是作为计数器的模式

截图202312301341442207.jpg


定时器是系统内部时钟进行计数
计数器就是通过外部引脚输入的脉冲信号计数,可以借助编码器用于电机测速
冲哥利用了按键模拟脉冲信号,要配置内部引脚的上拉电阻才可以做到电平从高到低的转变
stc-isp软件中有快速配置的方法
截图202312301635502930.jpg 截图202312301636589281.jpg

看冲哥视频,是脉冲下降沿计数,按键按下,电平由高-低-高,有一个下降沿
计数溢出产生中断,在中断中把LED引脚电平取反
但是如果实际中要用到上升沿或者双边沿计数怎么办?怎么配置呢?想请教一下各位
手上有一个旋转编码器,就只能用编码器测试一下了
这里用的是定时器1作为串口1的波特率发生器,定时器0计数,不断向串口发送当前计数值
给大家看一下

1703926476906.mp4

7.17 MB, 下载次数: 208

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-30 17:02:00 | 显示全部楼层
Crysta*** 发表于 2023-12-30 16:56
感谢STC!实验箱已经在路上了!如此良心!不愧是国产单片机/MCU的领航者,1T 8051单片机的领导者,32位8051 ...
  1. #include <STC32G.H>
  2. #include <stdio.h>
  3. unsigned int count = 0;
  4. void System_Init()
  5. {
  6.         EAXFR = 1;
  7.         CKCON = 0x00;
  8.         WTST = 0x00;
  9.         //高阻输入模式
  10.         P3M0 = 0x00; P3M1 = 0x10;
  11.         EA = 1;
  12. }
  13. void Uart1Init(void)                //9600bps@24.000MHz
  14. {
  15.         SCON = 0x50;                //8位数据,可变波特率
  16.         AUXR |= 0x40;                //定时器时钟1T模式
  17.         AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
  18.         TMOD &= 0x0F;                //设置定时器模式
  19.         TL1 = 0x8F;                        //设置定时初始值
  20.         TH1 = 0xFD;                        //设置定时初始值
  21.         ET1 = 0;                        //禁止定时器中断
  22.         TR1 = 1;                        //定时器1开始计时
  23. }
  24. void Timer0_Count()
  25. {
  26.         TMOD = TMOD|0x04; // 16位计数模式
  27.         TL0 = 0xff;
  28.         TH0 = 0xff;
  29.         ET0 = 1;
  30.         TR0 = 1;
  31. }
  32. void Timer0_handler() interrupt 1
  33. {
  34.         count++;
  35. }
  36. void UART_SendByte(unsigned char Byte)
  37. {
  38.         SBUF = Byte;
  39.         while(!TI);
  40.         TI = 0;
  41. }
  42. void main()
  43. {
  44.         System_Init();
  45.         Uart1Init();
  46.         Timer0_Count();
  47.         while(1)
  48.         {
  49.                 UART_SendByte((unsigned char)(count>>8));
  50.                 UART_SendByte((unsigned char)count);               
  51.         }
  52. }
复制代码
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:507
  • 最近打卡:2025-05-06 07:45:00
已绑定手机

1

主题

836

回帖

1517

积分

金牌会员

积分
1517
发表于 2023-12-28 08:04:27 | 显示全部楼层
参照试验箱电路图,试试自己制作开发板吧
靡不有初,鲜克有终
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-28 08:56:06 | 显示全部楼层
另外补充一点,GPIO口的端口一定要看清楚,如果要用到其他端口,要去数据手册查它的地址再用sfr定义,我还记得之前学stm32的时候,我为了点亮一个LED灯🥶,耗费了整整一个星期,还以为板子坏了,最后不经意间发现原来是GPIOE的引脚1被我写成了GPIOC的引脚1😓
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-28 08:57:00 | 显示全部楼层
小涵*** 发表于 2023-12-28 08:04
参照试验箱电路图,试试自己制作开发板吧

PCB不熟🤧
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:492
  • 最近打卡:2025-05-06 07:55:35
已绑定手机

27

主题

693

回帖

2000

积分

金牌会员

打工人

积分
2000
发表于 2023-12-28 10:20:48 | 显示全部楼层
Crysta*** 发表于 2023-12-28 08:56
另外补充一点,GPIO口的端口一定要看清楚,如果要用到其他端口,要去数据手册查它的地址再用sfr定义,我还 ...

包含一下头文件不就都有了么?
打工人
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:394
  • 最近打卡:2025-05-06 07:53:41

45

主题

381

回帖

1587

积分

金牌会员

静坐常思己过,闲谈莫论人非

积分
1587
发表于 2023-12-28 10:34:33 | 显示全部楼层
功到自然成,坚持学就会有的,要相信STC
处事要代人所想,读书需切己用功
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:394
  • 最近打卡:2025-05-06 07:53:41

45

主题

381

回帖

1587

积分

金牌会员

静坐常思己过,闲谈莫论人非

积分
1587
发表于 2023-12-28 10:54:49 | 显示全部楼层

1-1.png


图1

1-2.png

图2

1-3.png

pringf()函数原本是C语言中标准输入输出流中的函数,在STDIO.H头文件有声明。stc给的usb.h的头文件中将printf()函数进行了重定向,定向到了USB的HID模式中,这样你在C语言中使用printf函数时它就自动重定向到了USB中,这样你在串口助手中就可以看到printf打印的内容了。

处事要代人所想,读书需切己用功
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:394
  • 最近打卡:2025-05-06 07:53:41

45

主题

381

回帖

1587

积分

金牌会员

静坐常思己过,闲谈莫论人非

积分
1587
发表于 2023-12-28 10:58:08 | 显示全部楼层

作为一名合格的工程师,软硬件都要懂才行,不然出了问题都不知到根本原因在哪。慢慢学奥。
处事要代人所想,读书需切己用功
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:177
  • 最近打卡:2025-05-06 15:17:04
已绑定手机

17

主题

81

回帖

398

积分

中级会员

积分
398
发表于 2023-12-28 12:37:17 | 显示全部楼层
reng*** 发表于 2023-12-28 10:34
功到自然成,坚持学就会有的,要相信STC

嗯嗯
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-6 21:46 , Processed in 0.180814 second(s), 167 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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