Crystalline 发表于 2023-12-27 22:44:27

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

第四集
点亮第一个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灯的亮度




Crystalline 发表于 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

Crystalline 发表于 2023-12-28 14:11:43

本帖最后由 Crystalline 于 2023-12-28 16:01 编辑

第六集
LED闪烁和花式点灯
基本单位的换算
1s = 1000ms=1000000us
按照视频里的方法我发现LED闪烁的时间不是500ms,差不多1s
我开始怀疑是运行频率不对,
我看到stc-isp软件上的提示,去数据手册查了一下WTST寄存器才知道


下面把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);
      }
}

Crystalline 发表于 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了
{:4_183:}如果能收到实验箱的话,我再把这部分内容更新一下

Crystalline 发表于 2023-12-28 19:20:55

本帖最后由 Crystalline 于 2023-12-28 19:34 编辑

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

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




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



//假设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;
}



Crystalline 发表于 2023-12-28 20:13:00

第九集
静态数码管的使用

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




P67P66P65P64P63P62P61P60

dpgfedcba
011000000
111111100
210100100
310110000
410011001
510010010
610000010
711111000

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




Crystalline 发表于 2023-12-29 13:30:19

第十集

数码管的动态显示
数码管动态显示的原理就是利用人眼分辨不出50HZ以上的刷新率

只要让相邻两个数码管亮的间隔为1ms,在我们视角里它就是同时点亮的。
同时点亮八个数码管,逻辑就是:位选——段选——1ms延时——位选....
有一点我不明白,能不能让这个数码管亮的间隔更小呢?1us可以吗?

后面冲哥又以免单计数器给我们实战演练了一下动态数码管的应用,学一个东西马上就去实践它,好的教学!!!




Crystalline 发表于 2023-12-29 14:50:10

第十一集

定时器的使用




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




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





定时时间计算方法:




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






Crystalline 发表于 2023-12-30 16:56:52

本帖最后由 Crystalline 于 2023-12-30 16:57 编辑

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




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


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

Crystalline 发表于 2023-12-30 17:02:00

Crystalline 发表于 2023-12-30 16:56
感谢STC!实验箱已经在路上了!如此良心!不愧是国产单片机/MCU的领航者,1T 8051单片机的领导者,32位8051 ...
#include <STC32G.H>
#include <stdio.h>
unsigned int count = 0;

void System_Init()
{
      EAXFR = 1;
      CKCON = 0x00;
      WTST = 0x00;
      //高阻输入模式
      P3M0 = 0x00; P3M1 = 0x10;
      EA = 1;
}
void Uart1Init(void)                //9600bps@24.000MHz
{
      SCON = 0x50;                //8位数据,可变波特率
      AUXR |= 0x40;                //定时器时钟1T模式
      AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
      TMOD &= 0x0F;                //设置定时器模式
      TL1 = 0x8F;                        //设置定时初始值
      TH1 = 0xFD;                        //设置定时初始值
      ET1 = 0;                        //禁止定时器中断
      TR1 = 1;                        //定时器1开始计时
}
void Timer0_Count()
{
      TMOD = TMOD|0x04; // 16位计数模式
      TL0 = 0xff;
      TH0 = 0xff;
      ET0 = 1;
      TR0 = 1;
}
void Timer0_handler() interrupt 1
{
      count++;
}
void UART_SendByte(unsigned char Byte)
{
      SBUF = Byte;
      while(!TI);
      TI = 0;
}
void main()
{
      System_Init();
      Uart1Init();
      Timer0_Count();
      while(1)
      {
                UART_SendByte((unsigned char)(count>>8));
                UART_SendByte((unsigned char)count);               
      }
}

小涵子爸爸 发表于 2023-12-28 08:04:27

参照试验箱电路图,试试自己制作开发板吧

Crystalline 发表于 2023-12-28 08:56:06

另外补充一点,GPIO口的端口一定要看清楚,如果要用到其他端口,要去数据手册查它的地址再用sfr定义,我还记得之前学stm32的时候,我为了点亮一个LED灯🥶,耗费了整整一个星期,还以为板子坏了,最后不经意间发现原来是GPIOE的引脚1被我写成了GPIOC的引脚1😓

Crystalline 发表于 2023-12-28 08:57:00

小涵子爸爸 发表于 2023-12-28 08:04
参照试验箱电路图,试试自己制作开发板吧

PCB不熟🤧

zhudean11 发表于 2023-12-28 10:20:48

Crystalline 发表于 2023-12-28 08:56
另外补充一点,GPIO口的端口一定要看清楚,如果要用到其他端口,要去数据手册查它的地址再用sfr定义,我还 ...

包含一下头文件不就都有了么?

rengran 发表于 2023-12-28 10:34:33

功到自然成,坚持学就会有的,要相信STC{:4_175:}

rengran 发表于 2023-12-28 10:54:49

Crystalline 发表于 2023-12-27 23:45




图1


图2


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

rengran 发表于 2023-12-28 10:58:08

Crystalline 发表于 2023-12-28 08:57
PCB不熟🤧

作为一名合格的工程师,软硬件都要懂才行,不然出了问题都不知到根本原因在哪。慢慢学奥。

Crystalline 发表于 2023-12-28 12:37:17

rengran 发表于 2023-12-28 10:34
功到自然成,坚持学就会有的,要相信STC

{:loveliness:}嗯嗯
页: [1] 2 3 4
查看完整版本: STC32单片机学习记录 | 建议立即 【免费+包邮送】实验箱,提高学习效率