yuyy1989 发表于 2023-5-5 11:00:06

冲哥32位8051视频学习日记-已看到27集-实验箱到了

本帖最后由 yuyy1989 于 2023-6-1 21:48 编辑

实验箱到了感谢STC的支持,之后会把没能验证的代码在实验箱上验证一下



自学单片机,但从来没有系统的学习过,正好看视频好好了解一下

实际上手过程中越来越觉得STC-ISP这个工具的强大,不光是一个烧录工具


有这些功能初始化的程序写起来太方便了


即使没有相关设备也能用这里的虚拟设备来调试功能逻辑,只不过没法验证底层驱动逻辑,例如数码管的实现

yuyy1989 发表于 2023-5-5 11:04:54

第1集,主要介绍了什么是单片机,单片机的应用场景以及如何入门
个人觉得用51单片机入门更有助于对单片机原理的理解,有C语言的基础入门应该也会很快

yuyy1989 发表于 2023-5-5 11:17:06

本帖最后由 yuyy1989 于 2023-5-5 11:18 编辑

第2集,试验箱介绍,外设的工作原理,有开发经验的可以跳过这集
课后作业:结合实验箱上的外设做个时钟和温度表还是比较简单的

yuyy1989 发表于 2023-5-5 11:27:42

第3集,开发环境的搭建和程序烧录,真手把手地教,连怎么打开和查看PDF都教了
不过WIN10不用特地去下PDF阅读器,EDGE感觉就不错

yuyy1989 发表于 2023-5-5 14:06:15

第4集,点亮第一颗LED上,介绍了如何控制GPIO来点亮一颗LED,参考数据手册配置寄存器
这里用到了端口模式配置寄存器PxM0和PxM1,其中x为IO口的端口号,寄存器的bit0-bit7分别对应该端口的0-7号IO口,通过配置对应位为0或1配置IO口的模式


关于视频最后那个问题,从数据手册能看到除P3.0和P3.1外其余所有IO口上电后均为高阻输入状态(电流既不能流入也不能流出),如果注释掉配置IO口模式的代码是不能操作IO口点亮LED的,因此在使用IO口前必须配置IO口模式


yuyy1989 发表于 2023-5-5 15:15:25

本帖最后由 yuyy1989 于 2023-5-7 13:11 编辑

第4集,点亮第一颗LED下,USB-CDC/虚拟串口,不停电下载
STC的单片机支持USB直接下载而不用额外再用一个烧录器,这就很方便了,实现不停电下载后调试代码更方便了
isp软件设置,我的版本是6.91N和手册上的界面不大一样


实现方式也很简单,在工程里添加stc_usb_hid_32g.LIB(USB-HID模式)或stc_usb_cdc_32g.LIB(USB-CDC/串口模式),然后添加如下代码

//包含头文件
#include "../comm/usb.h" //USB调试及复位所需头文件

//main函数外的全局变量
//USB调试及复位所需定义
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";//设置自动复位到ISP区的用户接口命令

//main函数内while(1)前
WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
//USB调试及复位所需代码-----
P3M0 &= ~0x03;
P3M1 |= 0x03;
IRC48MCR = 0x80;
while (!(IRC48MCR & 0x01));
//如果使用USB-CDC需要下面的两行代码
USBCLK = 0x00;
USBCON = 0x90;
//如果使用USB-HID注释掉上面两行代码
usb_init();
//-------------------------
支持USB不停电下载的固件编译好之后需要用传统方式下载一次这个固件,之后就可以不停电下载了


课后练习:使用端口寄存器可以方便的一次性把该端口下的IO口全部拉高或拉低,例如P2.0-P2.7每个引脚都连接1颗LED,LED共阳极,代码中P2=0x00就可以点亮全部LED,P2=0xF0可以点亮P2.0-P2.3关掉P2.4-P2.7







yuyy1989 发表于 2023-5-5 21:17:55

第5集,C语言运算符和进制数入门,介绍了一些C语言的基础知识,有C语言基础的可以跳过这一集
刚接触单片机需要注意的是sbit P23=P2^3,这里的的^并不是进行异或运算,而是取寄存器的第3位

yuyy1989 发表于 2023-5-6 13:19:29

本帖最后由 yuyy1989 于 2023-5-7 13:13 编辑

第6集,LED闪烁和花式点灯,介绍了自适应时钟的Delay函数的实现,while循环的使用,#define的使用,函数的使用
#define MAIN_Fosc       24000000L   //定义主时钟
void delay_ms(uint16_t ms)
{
    uint16_t i;
    do{
      i = MAIN_Fosc / 6000;
      while(--i);   //6T per loop
    }while(--ms);
}
//在main函数的while(1)中添加
P20 = 0;
delay_ms(500);
P20 = 1;
delay_ms(500);
//实现P2.0IO控制的灯500ms亮500ms灭的循环闪烁
如果只是使用固定时间的延时可以用STC-ISP软件生成延时代码


关于--a和a--:--a会返回减1后的a值,a--会返回减1前的a值,++a和a++同理

课后练习:
//写一个闪烁的函数
void blinkLed(uint16_t onms,uint16_t offms,uint8_t count)
{
    while(count > 0)
    {
      P20 = 0;
      delay_ms(onms);
      P20 = 1;
      delay_ms(offms);
      count--;
    }
}
//在main函数的while(1)中添加
blinkLed(100,100,2);
blinkLed(100,500,1);
blinkLed(500,500,3);
blinkLed(100,100,3);
delay_ms(2000);


yuyy1989 发表于 2023-5-6 20:23:02

本帖最后由 yuyy1989 于 2023-5-7 13:15 编辑

第7集,按键点灯
//定义按键和LED
#define KEY0 P32
#define KEY1 P33
#define KEY2 P34
#define KEY3 P35
#define LED0 P20
#define LED1 P21
#define LED2 P22
#define LED3 P23
#define LED4 P24
#define LED5 P25
#define LED6 P26
#define LED7 P27

uint8_t keydown = 0x00;//使用bit0-bit3记录key0-key3的状态
uint8_t ledindex = 0;//0-4
uint8_t leddatas = {0xF7,0xEF,0xDF,0xBF,0x7F};

//按下KEY0 LED0亮,松开熄灭
void key0down_led0on()
{
    if(KEY0 == 0)
    {
      delay_ms(10);//去抖
      if(KEY0 == 0)
      {
            LED0 = 0;
      }
    }
    else
    {
      LED0 = 1;
    }
}

//按下KEY1 LED1熄灭,松开点亮
void key1down_led1off()
{
    if(KEY1 == 0)
    {
      delay_ms(10);//去抖
      if(KEY1 == 0)
      {
            LED1 = 1;
      }
    }
    else
    {
      LED1 = 0;
    }
}
//按下一次KEY2,LED2状态改变一次
void key2down_led2onoff()
{
    if(KEY2 == 0)
    {
      delay_ms(10);//去抖
      if(KEY2 == 0)
      {
            if((keydown&0x04) == 0)
            {
                keydown |= 0x04;
                LED2 = !LED2;
            }
      }
    }
    else
    {
      keydown &= 0xFB;
    }
}
//按下一次KEY3,LED3-LED7依次亮起一个
void key3down_led37on()
{
    if(KEY3 == 0)
    {
      delay_ms(10);//去抖
      if(KEY3 == 0)
      {
            if((keydown&0x08) == 0)
            {
                keydown |= 0x08;
                //if else 判断实现,此方法不要求LED全在同一个端口上
                /*
                if(LED3 == 0)
                {
                  LED3 = 1;
                  LED4 = 0;
                }
                else if(LED4 == 0)
                {
                  LED4 = 1;
                  LED5 = 0;
                }
                else if(LED5 == 0)
                {
                  LED5 = 1;
                  LED6 = 0;
                }
                else if(LED6 == 0)
                {
                  LED6 = 1;
                  LED7 = 0;
                }
                else
                {
                  LED7 = 1;
                  LED3 = 0;
                }
                */
                //移位方法
                //P2 = (P2 & 0x07)|(~(1<<(ledindex+3)));
                //数组方法
                P2 = leddatas;

                ledindex++;
                if(ledindex>4)
                {
                  ledindex = 0;
                }
            }
      }
    }
    else
    {
      keydown &= 0xF7;
    }
}
//在main函数的while(1)循环体前初始化LED状态
P2 = 0xFF;
//在main函数的while(1)循环体中放入
key0down_led0on();
key1down_led1off();
key2down_led2onoff();
key3down_led37on();



yuyy1989 发表于 2023-5-6 22:13:19

本帖最后由 yuyy1989 于 2023-5-7 13:16 编辑

第8集,蜂鸣器的应用
蜂鸣器分为有源蜂鸣器和无源蜂鸣器2种,有源蜂鸣器内部带有振荡源通电就会响,无源蜂鸣器内部无振荡源直接通直流信号不会响
#define KEY0 P32
#define KEY1 P33
#define KEY2 P34
#define KEY3 P35
#define LEDPORT P2
#define BEEP P54

uint8_t keydown = 0x00;//使用bit0-bit3记录key0-key3的状态
uint8_t funcindex = 0;//0-8功能档位
bit powerup = 0;//开关机状态
bit working = 0;//启动状态
uint8_t workingcount = 0;

//按下一次KEY0,蜂鸣器状态改变一次
void key0down_beeponoff()
{
    if(KEY0 == 0)
    {
      delay_ms(10);//去抖
      if(KEY0 == 0)
      {
            if((keydown&0x01) == 0)
            {
                keydown |= 0x01;
                BEEP = !BEEP;
            }
      }
    }
    else
    {
      keydown &= 0xFE;
    }
}

//按键1开关机
void key1_power()
{
    if(KEY1 == 0)
    {
      delay_ms(10);//去抖
      if(KEY1 == 0)
      {
            if((keydown&0x02) == 0)
            {
                keydown |= 0x02;
                if(powerup == 0) //当前关机,执行开机动作
                {
                  BEEP = 0;
                  delay_ms(10);
                  BEEP = 1;
                  LEDPORT = 0x00;
                  delay_ms(200);
                  LEDPORT = 0xFF;
                  powerup = 1;
                  funcindex = 0;
                  working = 0;
                }
                else//当前开机,执行关机动作
                {
                  BEEP = 0;
                  delay_ms(10);
                  BEEP = 1;
                  LEDPORT = 0xFF;
                  powerup = 0;
                }
            }
      }
    }
    else
    {
      keydown &= 0xFD;
    }
}

//按键2切换功能
void key2_func()
{
    if(powerup == 1 && working == 0)//已经开机且未启动
    {
      if(KEY2 == 0)
      {
            delay_ms(10);//去抖
            if(KEY2 == 0)
            {
                if((keydown&0x04) == 0)
                {
                  keydown |= 0x04;
                  funcindex += 1;
                  if(funcindex > 8)
                  {
                        funcindex = 1;
                  }
                  BEEP = 0;
                  delay_ms(10);
                  BEEP = 1;
                  LEDPORT = ~(1<<(funcindex-1));
                }
            }
      }
      else
      {
            keydown &= 0xFB;
      }
    }
}

//按键3启动或停止
void key3_work()
{
    if(powerup == 1 && funcindex > 0)//检查是否已开机并选择了功能
    {
      if(KEY3 == 0)
      {
            delay_ms(10);//去抖
            if(KEY3 == 0)
            {
                if((keydown&0x08) == 0)
                {
                  keydown |= 0x08;
                  BEEP = 0;
                  delay_ms(10);
                  BEEP = 1;
                  working = !working;
                  if(working == 0)
                  {
                        LEDPORT = ~(1<<(funcindex-1));
                  }
                }
            }
      }
      else
      {
            keydown &= 0xF7;
      }
      if(working == 1)
      {
            delay_ms(10); //延时太长影响按键按下的判断
            workingcount++;
            if(workingcount > 99)
            {
                workingcount = 0;
            }
            if(workingcount < 50)
            {
                LEDPORT = 0xFF;
            }
            else
            {
                LEDPORT = ~(1<<(funcindex-1));
            }
      }
    }
}

//在main函数的while(1)循环体中放入
key0down_beeponoff();
key1_power();
key2_func();
key3_work();
页: [1] 2 3 4
查看完整版本: 冲哥32位8051视频学习日记-已看到27集-实验箱到了