好学天上 发表于 2024-4-17 11:38:59

STC32G128K芯片学习打卡贴

本帖最后由 好学天上 于 2024-5-31 17:46 编辑

实验箱教学视频打卡

第一至三集 评论区打卡




第四集 点灯打卡 2024-04-18

LED点亮原理:两边电压差
GPIO:软件可以读取引脚输入电平或控制引脚输入电平(总算搞明白)
基本的书写规则
查找:ctrl+f
不掉电下载:根据视频加了lib文件和库文件,不知道为啥还是报错,也找了范例程序还是没找出原因。
作业点亮所以LED灯,按照之前学的,可以一个一个点亮P60 =0; P61=0....也可以P6=0x00即0000 0000八个口全置0点亮。
工程基本流程已掌握。
希望有老师可以解决一下我的问题
(os:讲课的老师手真好看嘻嘻)
已解决,没设置memory model,这也是和51不一样的地方;

第五集 C语言运算符打卡 2024-04-19

这节课的内容都比较基础,是在学校学C语言和单片机的时候都讲过
还有一个printf函数的使用,进制转换那些我们以前考试经常考的基础题,以及与或非之类的逻辑运算。还有变量类型以及它的大小。没有特别大的难度


第六集 流水灯打卡 2024-04-20

1. u16 → unsigned int
2.while和do while的区别:while一开始就做判断,判断条件为真则进入循环;do while会先执行一遍循环体,再做条件判断是否继续执行循环体;while比do while应用更多
3.--a和a--的区别: 若a=10; →--a=9;a=9;而a--=9;a=9a--是先进行取值,后进行自减;--a是先进行自减,后进行取值;
4.编程中常见小错误:忘记写分号;关键词写错;
5.#dedine用法,相当于把需要定义的内容换一个名字 。
哎哟 我已经掌握了图片排列的奥秘!
函数使用三步: 定义→声明→调用



课后练习:SOS灯光
没有一行一行写,但感觉应该有更简便的方法。

第七集 按键 打卡 2024-04-22

1.按键的原理:两个引脚间的通断:按下之后导通(常开);按下之后断开(常闭);
2.注意:机械开关断开闭合时都会有抖动,所以要靠变成消抖,判断按键状态后等待10ms后再次判断开关状态,此为消抖
3.按键应用:按下点亮松开熄灭;按下熄灭松开点亮;按一下取反;按一下led灯左移一位



4.数组的应用:定义→赋值,索引是长度减1,因为是从0开始。

5.课后作业:按下一次,LED右移一位


第八集 蜂鸣器 打卡 2024-04-23

1.蜂鸣器:无源蜂鸣器和有源蜂鸣器,区别是有源蜂鸣器内部有震荡,通电即可打开,而无源直流信号无法令其运行;
2.控制原理:和LED相同
3.电磁炉实战:按键配合LED和蜂鸣器,其实是把前几节课都结合起来了。

ps:老师好像没有在写第二个功能模式按键的时候做开机判断,这样即使在关机模式也可以功能切换吧。
4.课后作业:第三个启动按键,按下对应功能模式闪烁,且功能切换不可用


第九-十集数码管打卡 2024-04-24

1.数码管:多个发光二极管组成
2.控制原理:和LED类似,共阳给0亮,共阴给1亮
3.按键循环0-9:


4.静态显示作业:H 0x89;J 0xF0;L 0xC7;n 0xAD;o 0xA3;P 0x8C;U 0xC1;t 0x87;r 0x8F
按键1自加循环0-9,按键2控制蜂鸣器鸣叫对应数字次数


5.数码管动态显示原理:每一位数码管轮流点亮,但间隔时间只有1ms,是因为人无法分辨50Hz以上的刷新频率二产生视觉残留,看起来好像是一起亮的。
6.10秒免单计数器


7.注意事项:写代码过程中会有很多不注意的小细节,简单的书写错误,格式错误都会在最后要调试很多次,还是写得太少。
8.课后作业:简易时钟00.00.00,三十秒时闹钟响,蜂鸣器鸣叫3s;



本来想的是把闹钟设置直接放函数中判断,打开之后延时3s后关闭,但这样会干扰到本身的时钟运转,所以就设置了一个时钟标志位,将三秒的时间放入到时钟计数当中。但其实这种时钟计时方式应该本身就会不那么准确的。

第十一-十二集 定时计数器打卡 2024-04-25

1.定时器是定时/计数器的统称,定时器是硬件计时或每隔一段时间完成一次操作,可以替代长时间延时,提高CPU运行效率和处理速度,能及时响应某个事件;
2.相关的寄存器:TMOD,使用模式0定时器时,值为0x00;AUXR寄存器,设置分频,默认为12分频;定时器工作模式有模式0-16位自动重载,模式1-16位不自动重载,模式2-8位自动重载,模式3-不可屏蔽中断的16位自动重载,其中断优先级最高;
3.定时器初始化步骤:设置模式TMOD→设置分频AUXR→设置时间TH,TL→启动定时器TR0→使能定时器中断ET0→使能总中断EA
4.作业:用定时器驱动时钟并设置启动暂停按键
主函数
定时器函数;
5.计数器:计数器用途有电机测速等,输出信号带高低电平变化都可以用计数器;
6.计数器的配置:
按键P35每按下一次,led灯P60状态取反一次;

7.例程:电机测速模拟,用按键模拟脉冲


8.作业:2s周期改为每分钟:


9.思考:如果计数器溢出了程序要怎么写? 答:说实话这节课还有点云里雾里。

第十三集 TIM多任务处理打卡 2024-04-26

1.创建程序文件三步;程序定义三步,函数定义三步;这里前面的课程都有提到过。
2.extern:在a文件里要使用b文件的变量时,用extern在b的库文件中定义该变量,再在a.c中包含b的库文件;
3.bdata位寻址变量定义,例如定义一个八位变量使用bdata,可以分别定义八位的每一位,单独赋值。
4.static静态变量,静态变量时的赋值只一次有效;
5.数码管LED的程序文件:

2024-04-28接上文
6.按键的函数文件,不使用while循环,改用状态机的模式,在主函数中定时使用循环读取每个按键状态的函数,再在使用到某个按键时,使用另一个函数直接读取该按键的状态,返回定义好的状态返回值,有未按下,抖动,按下,按下结束,长按,长按结束这些状态,再在主函数当中通过判断该按键状态来书写功能函数:
key.h
key.c
主函数中功能实现

7.蜂鸣器的函数文件,通过设置蜂鸣器鸣叫时间的函数来决定蜂鸣器要不要叫,要叫多久,再在主函数中10ms循环运行蜂鸣器运行函数,当设置的时间等于0,蜂鸣器不鸣叫,大于0,则鸣叫该时间后关闭。
beep.h

beep.c

beep在主函数中调用使用。

8.定时器函数文件,只需要将之前在主函数写的定时器初始化移到定时器c文件中,在主函数里调用函数使用;而中断函数最好仍在主函数中书写,因其需要调用不同的功能函数,所以放在主函数更佳。
9.课后作业:
LED0每200ms取反一次;LED1每400ms取反一次;LED2每800ms取反一次
感觉这个方法不是那么聪明的样子;

改写电磁炉程序:


10.体会:主要是将程序都结构化,让看代码的人也能清晰易懂,修改优化程序时更方便。

第十四集 矩阵按键打卡 2024-04-29

1.矩阵按键:每行由一个IO口控制,每列由一个IO口控制,不同于独立按键的一对一IO口,可以大大节省硬件资源;
2.控制原理:通过扫描行和列,判断按键按下位置,类似二维坐标;先将行IO都置低电平,列置高电平,确定哪一列;再将行置高电平,列置低电平,确定哪一行;通过二者确定按键位置;


3.实践程序:电子门锁----矩阵按键输入八位密码,密码正确门开则LED亮,密码错误蜂鸣器鸣叫2s后关闭;每次按键输入蜂鸣器鸣叫20ms。
+课后作业:门锁打开5s后自动关闭,切回锁定状态,设置门内手动开门按钮,使用独立按键,可以一键直接开门;10s内无操作数码管熄灭,有操作即点亮。
#include "COMM/stc.h"
#include "COMM/usb.h"
#include "led_seg.h"
#include "key.h"
#include "beep.h"
#include "time0.h"

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";                      //设置自动复位到ISP区的用户接口命令
bit TIME_10MS = 0; //10ms标志位


void delay_ms(u16 ms);
void sys_init(void);
#define MAIN_Fosc    24000000UL
u16 timi = 0;

void main()//程序开始运行的入口
{
u8 key_num = 0; //矩阵按键键值
      u8 key_str = 0; //密码输入数量
      u8 i;
      u32 count = 0;//计时单位
      bit flag = 0;//门锁是否开启标志
      sys_init();//USB功能+IO初始化
      usb_init();//USB CDC 接口配置
      
      Timer0_Init();
      EA = 1;//打开总中断
      
      SEG0 = SEG1 = SEG2 = SEG3 = SEG4 = SEG5 = SEG6 = SEG7 =22;//初始显示--------
      LED = 0xff;//数码管和LED显示
   
      while(1)      //死循环
      {
                if(DeviceState != DEVSTATE_CONFIGURED)
                        continue;
                if(bUsbOutReady)
                {
                        usb_OUT_done();//接受应答(固定格式)
                }
                if(TIME_10MS == 1) //10ms刷新一次
                {
                        TIME_10MS =0;
                        count++;
                        BEEP_RUN(); //蜂鸣器运行
                        KEY_Deal(); //读取按键状态
                        key_num = MatrixKEY_Read(); //获取键值
                        if(count == 100) //10s时数码管全都关闭
                        {
                              count = 0;
                              SEG0 = SEG1 = SEG2 = SEG3 = SEG4 = SEG5 = SEG6 = SEG7 =21;
                        }
                        if(key_num > 0)//有按键按下
                        {
                              count = 0; //有按键按下时,重新计算10s
                              BEEP_ON(2); //每次按键按下蜂鸣器叫20ms
                              key_str++; //密码位数++
                              show_Tab = key_num; //数码管显示输入值
                              if(key_str > 8) //输入密码已达八位
                              {
                                        key_str = 0; //初始化密码位数
                                        for(i = 0; i < 8; i++)
                                        {
                                                if(show_Tab == 1) //判断每一位都等于1否
                                                {
                                                      flag = 1; //密码一致
                                                }
                                                else
                                                {
                                                      flag = 0; //有任何一位不一致,返回门锁未开标志,退出循环
                                                      break;
                                                }
                                        }
                                        if(flag == 1 )//门锁已开,灯亮
                                        {
                                                LED0 = 0;
                                                delay_ms(5000); //门开后5s,继续上锁,返回门锁上标志
                                                flag = 0;
                                        }
                                        else if(flag == 0) //门锁关闭,蜂鸣器鸣叫2s,灯灭
                                        {
                                                BEEP_ON(20);
                                                LED0 = 1;
                                        }
                                        SEG0 = SEG1 = SEG2 = SEG3 = SEG4 = SEG5 = SEG6 = SEG7 =22;
                              }
                              key_num = 0;
                        }
                }
                if(KEY_ReadState(KEY1) == KEY_PRESS) //按下按键1,门直接打开
                {
                        flag = 1;
                }
      }
}

void Timer0_Isr(void) interrupt 1
{
      static time_count = 0;
      SEG_refresh();                //刷新数码管
      time_count++;
      if(time_count >= 10)
      {
                TIME_10MS = 1;//10ms时间到
    time_count = 0;
      }
}

void Timer1_Isr(void) interrupt 3
{
      
}
void sys_init()
{
    WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    //====== USB 初始化 ======
    P3M0 &= ~0x03;
    P3M1 |= 0x03;
   
    IRC48MCR = 0x80;
    while (!(IRC48MCR & 0x01));
   
    USBCLK = 0x00;
    USBCON = 0x90;
    //========================
}

void delay_ms(u16 ms)
{
      u16 i;
      do
      {
                i=MAIN_Fosc/6000;
                while(--i);
      }
      while(--ms);
}
第十五集 外部中断打卡 2024-04-29

1.中断系统:CPU处理紧急事件的功能部件。优点:a.总是响应优先级最高的中断请求;b.每个中断源都可以独立控制开关;c.低优先级中断处理中可以被高优先级中断打断;d.部分中断源优先级可以通过软件改变。
2.外部中断:单片机的一个引脚上由于外部因素造成的电平变化(如按键按下),引起的中断就是外部中断.单片机原理图标了INTx的就是外部中断口.
3.外部中断使用:
void INT0_init(void)//外部中断初始化函数
{
      IT0 = 1;//1为下降沿有效,0为上升沿下降沿均可触发
      EX0 = 1;//中断允许
      IE0 = 0;//清楚中断标志
}//外部中断0初始化


//中断功能函数
弄清中断使用的寄存器的每个标志位的高低电平分别是什么功能.
4.课后作业:写外部中断1和中断2-4的函数
void INT1_init(void)//外部中断1
{
IT1 = 1;//1为下降沿有效,0为上升沿下降沿均可触发
      EX1 = 1;//中断允许
      IE1 = 0;//清楚中断标志
}

void INT1_isr(void) interrupt 2
{
      //功能
}


void INT2_init(void)//外部中断2
{
//只能下降沿触发
      EX2 = 1;//中断允许
}

void INT2_isr(void) interrupt 10
{
      //功能
}

void INT3_init(void)//外部中断3
{
//只能下降沿触发
      EX3 = 1;//中断允许
}

void INT3_isr(void) interrupt 11
{
      //功能
}

void INT4_init(void)//外部中断4
{
//只能下降沿触发
      EX4 = 1;//中断允许
}

void INT4_isr(void) interrupt 16
{
      //功能
}思考:什么时候用外部中断?
之前学的定时器中断使用在周期性中断,一定时间才会处理一次事件,而外部中断,只要有外部触发就可以产生中断,优先处理,且执行完以后会自己继续执行主程序。可以用外部中断来写之前按键的功能函数。


第十六集 IO中断打卡 2024-04-30

1.IO中断:普通IO口均可中断,有四种触发方式,低电平、高电平、上升沿、下降沿;stc32暂时别用上升沿和下降沿触发方式;
2.IO中断和外部中断的区别:外部中断只能单次触发,用下降沿触发;IO口使用高电平,低电平触发,可以持续进入中断,例如按键按住不放,持续低电平,按下有效,松开无效;
3.IO中断相关寄存器: PnIM1 PnIM0 --设置触发方式;INTE -- 中断使能,0关1开;INTF -- 中断标志寄存器 0无中断请求,1有中断请求,若使能中断了,标志位需软件清零;PnIPH PnIP -- 设置中断优先级 00-11,00是最低的11是最高的;
void P3EXIT_init(void)
{
      P3IM0 = 0X00;
      P3IM1 = 0XFF;                                        //M1 M0 = 10 低电平中断
      P3INTE = 0X20;                                        //p35中断0010 0000
}//IO中断初始化程序
4.实践:八个按键对应八个LED灯,按键按下灯亮门开,灯灭门锁;一个独立按键模拟应急按钮,按下门全开,且不能用按键解锁,再次按下应急按钮则五秒后解锁:
void main()//程序开始运行的入口
{
u8 key_num = 0; //矩阵按键键值
      u8 key_str = 0; //密码输入数量
      bit flag = 0;//门锁是否开启标志
      sys_init();//USB功能+IO初始化
      usb_init();//USB CDC 接口配置
      
      Timer0_Init();
      EA = 1;//打开总中断
      
      SEG0 = SEG1 = SEG2 = SEG3 = SEG4 = SEG5 = SEG6 = SEG7 =22;//初始显示--------
      LED = 0xff;//数码管和LED显示
   
      while(1)      //死循环
      {
                if(DeviceState != DEVSTATE_CONFIGURED)
                        continue;
                if(bUsbOutReady)
                {
                        usb_OUT_done();//接受应答(固定格式)
                }
                if(TIME_10MS == 1)
                {
                        TIME_10MS = 0;
                        if( Tcount ==0 )                                                                //如果没有按下过应急按钮
                        {
                              key_num = MatrixKEY_Read();                                                //当前矩阵按键的键值1-8
                              BEEP_RUN();                                                                              //蜂鸣运行
                              if( key_num > 0 )                                                                        //如果有按键拿下
                              {
                                        BEEP_ON(2);
                                        flag ^=(1<<(key_num-1));                        //获取当前是第几个按钮按下,{1-8}-》
                              }
                              LED = flag;                                                                //初始状态熄灭所有LED
                              SEG0 = 21;                                                                              //熄灭数码管
                        }
                        else                                                                                                //按下了应急按钮
                        {
                              Tcount--;
                              SEG0 = (Tcount/100+1);                                        //500/100 499
                        }
                }
                        
      }
}//主程序
void P3EXIT_isr(void) interrupt 40
{
      u8 intf;
      intf = P3INTF ;//中断标志寄存器
      if (intf)
      {
                P3INTF = 0x00;//清零标志位
                if(intf & 0x20)
                {
                        LED = 0x00;                        //打开所有门锁
                        SEG0 = 5;                        //数码管持续显示5
                        Tcount = 500;//5秒倒计时的一个变化
                }
      }
}
//中断功能函数
5.课后作业:
按下P35四位秒表50s倒计时,最小单位10ms;P54中断,低电平触发,按下SEG1从0-9计数;设置P54优先级高于P35,可以中断秒表计时
void P3EXIT_init(void)
{
      P3IM0 = 0X00;
      P3IM1 = 0XFF;                                        //M1 M0 = 10 低电平中断
      P3INTE = 0X20;                                        //p35中断0010 0000
}

//void P3EXIT_init(void) interrupt 31 写在主函数

void P5EXIT_init(void)
{
      P5IM0 = 0X00;
      P5IM1 = 0XFF;                                        //M1 M0 = 10 低电平中断
      IPH = 0;
      IP= 1;//优先级设为1,这样就高于P3
      P5INTE = 0X20;                                        //p54中断0001 0000
}//初始化中断函数
void main()//程序开始运行的入口
{
u8 key_num = 0; //矩阵按键键值
      u8 key_str = 0; //密码输入数量

      sys_init();//USB功能+IO初始化
      usb_init();//USB CDC 接口配置
      
      Timer0_Init();
      EA = 1;//打开总中断
      
      SEG0 = SEG1 = SEG2 = SEG3 = SEG4 = SEG5 = SEG6 = SEG7 =21;//初始显示--------
      LED = 0xff;//数码管和LED显示
   
      while(1)      //死循环
      {
                if(DeviceState != DEVSTATE_CONFIGURED)
                        continue;
                if(bUsbOutReady)
                {
                        usb_OUT_done();//接受应答(固定格式)
                }
                if(TIME_10MS == 1)
                {
                        TIME_10MS = 0;                        if(flag != 1)
                        {
                              if(Tcount > 0)
                              {
                                        Tcount--;
                                        SEG4 = 0;//ms
                                        SEG5 = Tcount/10; //10ms
                                        SEG6 = Tcount/100;//1s
                                        SEG7 = Tcount/1000;//10s
                              }
                        }
                        else
                        {
                              SEG1 += 1;//数码管1数字加一
                        }
                }
                        
      }
}void P3EXIT_isr(void) interrupt 31
{
      u8 intf;
      intf = P3INTF ;//中断标志寄存器
      if (intf)
      {
                P3INTF = 0x00;//清零标志位
                if(intf & 0x20)
                {
//                        LED = 0x00;                        //打开所有门锁
//                        SEG0 = 5;                        //数码管持续显示5
//                        Tcount = 500;//5秒倒计时的一个变化
                        Tcount = 5000; //50s
                        SEG4 = 0;//ms
                        SEG5 = 0; //10ms
                        SEG6 = 0;//1s
                        SEG7 = 5;//10s
                        
                }
      }
}

void P5EXIT_isr(void) interrupt 42
{
      u8 intf;
      intf = P5INTF ;//中断标志寄存器
      if (intf)
      {
                P5INTF = 0x00;//清零标志位
                if(intf & 0x10)//P54
                {
                        flag = 1;
                   SEG1 = 0;//数码管1循环显示0-9
                }
      }
}//主函数和中断功能函数
感觉我这个代码还是有很大问题的,没关系等我实验箱到了我就可以根据一一调试了,我实验箱后天就要到了哈哈哈哈哈哈哈哈哈哈{:lol:}

第十七集 ADC采集打卡 2024-05-06

1.ADC:analog to digital converter 模数转换器
2.12位高速A/D转换器:ADC数值占十二位;

3.ADC相关寄存器:ADC控制寄存器(ADC_CONTR)包括ADC电源开关位,ADC转换启动位,ADC转换结束标志位,ADCPWM使能标志位,ADC模拟通道选择位;ADC配置寄存器(ADCCFG);ADC时序控制寄存器(ADCTIM)
4.ADC查询功能初始化
//========================================================================
      // 函数名称: ADC_init()
      // 函数功能: ADC查询初始化
      // 入口参数: 无
      // 函数返回: 无
      // 当前版本: VER1.0
      // 修改日期: 2024-05-06
      // 当前作者:
      // 其他备注:
      //========================================================================
      void ADC_init(void)
      {
                P1M0 = 0x00;
                P1M1 = 0x01;   //设置P1.0为ADC口,高阻输入
                ADCTIM = 0x3F; //设置ADC内部时序
                ADCCFG = 0x2F; //设置ADC系统时钟为fosc/2/16,右对齐
                ADC_POWER = 1; //使能ADC模块
      }
      //========================================================================
      // 函数名称: ADC_Read
      // 函数功能: 读取指定通道的adc电压
      // 入口参数: @no:通道0-15
      // 函数返回: 当前的12位adc数值
      // 当前版本: VER1.0
      // 修改日期: 2024-05-07
      // 当前作者:
      // 其他备注:
      //========================================================================

      u16 ADC_Read(u8 no)
      {
                u16 adcval;   //adc数值保存变量
                ADC_CONTR &= 0xf0;//清空通道选择
                ADC_CONTR |= no;    //选择通道
                ADC_START = 1;      //开启ADC转化
                _nop_();       //空操作指令,延时作用
                _nop_();
                while(!ADC_FLAG);   //等待ADC转换结束,结束flag会变成1,1取反变成0,0退出循环
                ADC_FLAG = 0;   //ADC转换结束标志位置0,以便下次转换
                adcval = (ADC_RES << 8) + ADC_RESL;//高四位左移八位再与低八位相加得出adc数值
                adc_val = adcval;//
                return adcval;
      }
      //ADC查询相关定义ADC中断功能初始化
#elif ADC_FUNC == ADC_isr
      //========================================================================
      // 函数名称: ADC_init()
      // 函数功能: 中断ADC初始化
      // 入口参数: 无
      // 函数返回: 无
      // 当前版本: VER1.0
      // 修改日期: 2024-05-06
      // 当前作者:
      // 其他备注:
      //========================================================================
      void ADC_init(void)
      {
                P1M0 = 0x00;
                P1M1 = 0x01;   //设置P1.0为ADC口,高阻输入
                ADCTIM = 0x3F; //设置ADC内部时序
                ADCCFG = 0x2F; //设置ADC系统时钟为fosc/2/16,右对齐
                ADC_POWER = 1; //使能ADC模块
               
                EADC = 1;      //打开ADC中断
                ADC_START = 1; //开启ADC转化
      }
      //========================================================================
      // 函数名称: ADC_isr
      // 函数功能: ADC中断函数
      // 入口参数: 无
      // 函数返回: 无
      // 当前版本: VER1.0
      // 修改日期: 2024-05-09
      // 当前作者:
      // 其他备注:
      //========================================================================
      void ADC_isr() interrupt 5//ADC中断函数
      {
                ADC_flag = 0;//清空读取标志位
                adc_val= (ADC_RESL << 8) + ADC_RESL; //读取ADC数值
                ADC_START = 1; //开启ADC转化
      }
      //ADC中断的相关定义用到if预定义,来选择中断或查询功能。
ADC数值转换成电压值函数:
u16 ADC_CAL_VOLTAGE(u16 num)
{
      return num*2.5*1000 / 4096;//ADC值*2.5v*0.001V(转成mv)/4096(最大数值)
}5.作业 :前四位显示数值,后四位显示电压,超过2.2V蜂鸣器常响(我改成LED0常亮)
代码
if(TIME_10MS == 1)
                {
                        TIME_10MS = 0;
                        ADC_Read(0);//读取ADC0的值,也就是ADC16个按键,0-F分别为256,..,4095,加256一级
                        SEG0 = (int)adc_val/1000;
                        SEG1 = (int)adc_val/100%10;
                        SEG2 = (int)adc_val/10%10;
                        SEG3 = (int)adc_val%10;
                        SEG4 = (int)ADC_CAL_VOLTAGE(adc_val)/1000;
                        SEG5 = (int)ADC_CAL_VOLTAGE(adc_val)/100%10;
                        SEG6 = (int)ADC_CAL_VOLTAGE(adc_val)/10%10;
                        SEG7 = (int)ADC_CAL_VOLTAGE(adc_val)%10;
                        //printf("当前ADC数\xfd值:%d\t%dmv\r\n",(int)adc_val,(int)ADC_CAL_VOLTAGE(adc_val));
                        if((int)ADC_CAL_VOLTAGE(adc_val) > 2200)
                        {
                              LED0 = 0;
                        }
                        else
                              LED0 = 1;
                }效果


看了两遍终于结束这一课了,{:victory:}

第十八集 ADC应用打卡 2024-05-07~14 拖拖拉拉
1.用ADC15通道反推电源电压:外部通道输入电压=内部参考信号源电压/内部参考信号源ADC测量值*外部通道输入ADC测量值
u16 ADC_VrefCal(void)
      {
                u8 i;
                int res;
                int vcc;
                BGV = ((VREFH_ADDR << 8) + VREFL_ADDR);//从CHIPID中读取内部参考电压值
                ADC_init();    //ADC初始化,ADC15内部参考信号源1.19V,不用设置端口高阻输入,所以可以直接使用初始化函数
                ADC_Read(15);//丢弃前几次数据,刚上电读取数值不稳定
                ADC_Read(15);
                ADC_Read(15);
                ADC_Read(15);
                for(i=0;i<8;i++)//读取八次数据,保证数据准确
                {
                        res += ADC_Read(15);//内部参考信号源ADC数值
                }
                res >>=3;//右移3位,除以8取平均值
                vcc = (int)(4096L * BGV/res);   //(12位ADC算法)计算VREF管脚电压,即电池电压;4096L是外部通道输入电压ADC测量值
                return vcc;   //返回电压值
      }2.ADC扫描按键(自动循环):

#define ADC_OFFSET 64//ADC误差允许

u8 ADC_keyread(u16 adc)
{
      u8 i;
      u16 adc_cmp;   //当前adc数值和每个按键代表adc数值adc_cmp比较
      static u8 key_last = 0;   //按键上一次的状态
      static u16 key_downtime;//按下时间(长按/短按)
      
      //按钮有无按下,第一个按键按下adc是256
      if(adc < (256 - ADC_OFFSET))   //adc数值小于256-误差允许,没有按键按下,值为0
      {
                key_downtime = 0;   //没有按键按下,按下时间为0
                key_last = 0;         //上一次按键状态清零
      }
      adc_cmp = 256;   //有按键按下时,从第一个按键初始值开始比较,依次加256判断是第几个按键
      for(i=1;i<=16;i++)//循环16次,依次与16个按键比较,键值i从1开始
      {
                if((adc >= (adc_cmp - ADC_OFFSET)) && (adc <= (adc_cmp + ADC_OFFSET)))//检测到adc数值跟每个按键数值比较,误差±64
                {
                        //return i;//满足本次判断,返回该减值,并退出循环,不执行后面
                        break;
                }
                else
                        adc_cmp += 256;//不满足单次判断,adc_cmp+256,继续比较
      }
      
      if(i>16)//循环都执行完了,没有键值满足
      {
                key_downtime = 0;//即没有按键按下,这个变量清零
                key_last = 0;      //上一次按键状态清零
      }
      else//有按键按下,判断按下时间
      {
                if(key_last == i)//上一次按键等于这一次按键状态,说明按键是一直按下的
                {
                        key_downtime ++;//按下时间加1
                        if(key_downtime == 3)//主函数每10ms扫描一次,当按下时间等于3时,即30ms
                        {
                              return i;//还是返回该键值
                        }
                        else if(key_downtime == 300)//长按3秒
                        {
                              key_downtime = 290; //长按3秒后每10ms触发一次长按功能
                              return i+0x80;
                        }
                        else
                              return 0;
                }
                else
                {
                        key_downtime = 0;//刚按下按下时间还未加
                        key_last = i;   //保留按键状态,以便开始按键时间计数
                }
      }
      return 0; //3.实战小练(简易时钟)+课后作业(闹钟设置):


虽然描述很简单,思考的过程很漫长,花了很多的时间去理解老师的代码,又花了很多时间想闹钟设置,一步一步调试代码,再加上自己遇难则退,就拖拖拉拉了一个礼拜了。后面要抓紧了,毕竟还有活要干叻。。{:mad:}


第十九集 NTC温度测温打卡 2024-05-14~05-16

1.NTC原理:Negative Temparature Coefficient,热敏电阻的特性温度越高,电阻的阻值呈指数下降
2.NTC测温程序:单片机的ADC3通道接的NTC电路,通过读取ADC2的adc数值来对照不同等级adc值获取对应温度;
//========================================================================
// 函数名称: temp_cal
// 函数功能: 通过读取的adc数值计算出温度。
// 入口参数: @adc
// 函数返回: 当前的温度值,保留一位小数,-40到150度的温度对应数值-400~1500
// 当前版本: VER1.0
// 修改日期: 2024-05-14
// 当前作者:
// 其他备注: int -32678~32767
//========================================================================
int temp_cal(u16 adc)
{
      u8 i;//循环比较变量
      float temp;//温度中间变量
      
      if(adc > adc_table)//比-40温度对应adc值还要大,超出范围
                return -32678;    //超出返回值
      else if (adc < adc_table)   //比150度对应adc值还要小,超出范围
                return 32767;    //超出返回值
      else//adc值在NTC范围内
      {
                for(i=0;i<190;i++)   //遍历ADC值对应温度表,从-40度开始比较
          {
                        if(adc == adc_table)//正好等于该等级adc数值
                        {
                              return (i-40)*10; //序号减去40,加一位小数乘以10
                        }
                        else if(adc<adc_table)//小于,不处理
                        {
                              
                        }
                        else   //大于adc_table,adc_table的值加上算出小数点值
                        {
                              i = i - 1; //
                              temp = adc_table - adc; //adc-标准值的余量即为小数部分adc值
                              temp = temp*10/(adc_table - adc_table);//adc转温度值
                              temp += (i-40)*10; //小数部分加上整数部分
                              return temp;
                        }
                }
      }
}3.实战小练加课后作业:简易温度计,数码管显示温度保留小数点后一位,开关机按键,按一下取反;测量按键,按下读取温度20次后取平均值显示,测量完成LED亮3s;30s不操作自动关机;


温度读取老师教的没有花多少时间;功能处理花了很多时间,感觉自己逻辑很差,每次第一次从头顺下来的逻辑都是错的,基本上要从头到尾全部改一遍;再加上粗心导致的问题,有时候系统不会报错就会花很多时间才能发现问题,可能就是变量的名字取得很相似,搞混了,还有一些时间计数变量,太多了导致弄混了,都要花很多时间找出来。{:4_257:}

第二十-二十一集 串口通信打卡 2024-05-16~05-18

1.通信:串口通信(每次发送一位数据),并行通信(多位数据一起发)
2.串口通信:外设和计算机之间通过数据信号线、地线、控制线等,按位传输数据;传输双方波特率、校验位、停止位、数据位都要一致;
3.STC32串口通信:全双工(可以同时收发),异步通信()
4.串口通信代码实现:
#define BRT   (65536-(MAIN_FOSC/115200+2)/4)   //加2操作是为了让keil编译器自动实现四舍五入运算

bit busy;   //忙碌标志位
char wptr;//发送计数
char rptr;//接收计数
char buffer;//接收缓冲

void usart2_init(void)
{
      P_SW2 = 0x80;   //串口2功能脚切换寄存器
      P_SW2 |= 0x01;//将串口2的引脚切换到P46 P47,且不改变第一步的设置
      
      S2CFG = 0x01;   //串口2配置寄存器   要用串口2必须设置该寄存器最后一位W1为1,不用可不特别设置
      S2CON = 0x50;   //串口2控制寄存器   选择模式2工作方式,固定波特率9位数据方式
      T2L   = BRT;    //
      T2H   = BRT >> 8;
      T2x12 = 1;
      T2R   = 1;
      wptr= 0x00;
      rptr= 0x00;
      busy= 0;
}

void usart2_isr() interrupt 8
{
      if(S2TI)
      {
                S2TI = 0;
                busy = 0;
      }
      if(S2RI)
      {
                S2RI = 0;
                buffer = S2BUF;
                wptr &= 0x0f;
      }
}

void usart2_send(char dat)
{
      while(busy);
      busy = 1;
      S2BUF = dat;
}

void usart2_sendstr(char *p)
{
      while(*p)//到停止位结束
      {
                usart2_send(*p++);
      }
}主程序
usart2_sendstr("Uart Test!\r\n");5.串口通信应用:copy实例里的串口设置函数。二十集的作业独立思考完成不了。。
/*
项目名称:简易串口控制器。

1.串口发送字符      Ax\r\n,(x表示0-7)板子点亮对应LED
2.串口发送                Bxxxx\r\n,xxxx表示一个四位数,四位数码管显示这个4位数
2.串口发送                Z\r\n,板子给电脑发送“Hello STC”;
3.串口发送字符      Cx\r\n,(x表示0-1)板子打开/关闭蜂鸣
4.串口发送字符      D\r\n,板子通过串口发送当前温度给电脑。

*/temp = temp_cal(ADC_Read(3));
                if(Rec_Flag == 1)
                {
                        switch(RX2_Buffer)
                        {
                              case 'A':
                                        if((RX2_Buffer >= 48) && (RX2_Buffer <= 55))//0-9的ASCII码
                                        {
                                                LED = ~(1<<(RX2_Buffer-48));
                                        }
                                        break;
                              case 'B':
                                        SEG0= RX2_Buffer-48;SEG1= RX2_Buffer-48;SEG2= RX2_Buffer-48;SEG3= RX2_Buffer-48;
                                        break;
                              case 'C':
                                        if(RX2_Buffer == 48)
                                                BEEP = 0;
                                        else
                                                BEEP = 1;
                                        break;
                              case 'D':
                                        sprintf(str,"当前温度:%d\r\n",temp);                                  PrintString2(str);
                                        break;
                              case 'Z':
                                        PrintString2("Hello STC!");
                                        break;
                              default:
                                        break;
                        }
                        Rec_Flag = 0;
                }6.课后作业:串口控制PC(ADC按键配合)
按下按钮0-7,发送“Ax\r\n”,x:0-7;
按下8,发送“B0000\r\n”;
按下9,发送“Z\r\n”;
按下A,发送“C0\r\n”;按下B,发送“C1\r\n”;
按下C,发送“Dx\r\n”;
keynum = ADC_keyread(ADC_Read(0));
                switch(keynum)
                {
                        case 1:
                        case 2:
                        case 3:
                        case 4:
                        case 5:
                        case 6:
                        case 7:
                        case 8:
                              sprintf(str,"A%d\r\n",keynum-1);
                              PrintString2(str);
                        break;
                        case 9:
                              PrintString2("B0000\r\n");
                        break;
                        case 10:
                              PrintString2("Z\r\n");
                        break;
                        case 11:
                              PrintString2("C0\r\n");
                  break;
                        case 12:
                              PrintString2("C1\r\n");
                              break;
                        case 13:
                              PrintString2("Dx\r\n");
                        break;
                        default:
                              break;
                }终于终于学到串口通信,就是因为学习研发卡死在串口通信第一步,才开始重头学单片机哈哈,希望这次不要忘得太快{:4_244:}


第二十二集 CDC串口通信打卡 2024-05-20

CDC串口通信和传统串口通信区别:
可以不断电下载;
串口通信波特率随便选也不会出错;
传统打印字符要通过sprintf转化变量为字符,CDC可以直接使用printf;
使用简单可能是可以直接用例程里的代码;
只需要一根线,usb线又供电又通信。
void main()//程序开始运行的入口
{
      int temp;   //温度
      sys_init();//USB功能+IO初始化
      usb_init();//USB CDC 接口配置
      EUSB = 1;
      
      Timer0_Init();
      ADC_init();
      P1M0 = 0x00; P1M1 = 0x08;
      EA = 1;//打开总中断
      while(DeviceState != DEVSTATE_CONFIGURED);
   
      while(1)      //死循环
      {
                delay_ms(2);
                temp = temp_cal(ADC_Read(3));
                if(bUsbOutReady)
                {
                        usb_OUT_done();//接受应答(固定格式)
                        switch(UsbOutBuffer)
                        {
                              case 'A':
                                        if((UsbOutBuffer >= 48) && (UsbOutBuffer <= 55))//0-9的ASCII码
                                        {
                                                LED = ~(1<<(UsbOutBuffer-48));
                                        }
                                        break;
                              case 'B':
                                        SEG0= UsbOutBuffer-48;SEG1= UsbOutBuffer-48;SEG2= UsbOutBuffer-48;SEG3= UsbOutBuffer-48;
                                        break;
                              case 'C':
                                        if(UsbOutBuffer == 48)
                                                BEEP = 0;
                                        else
                                                BEEP = 1;
                                        break;
                              case 'D':
                                        printf("当前温度:%d\r\n",temp);
                                        break;
                              case 'Z':
                                        printf("Hello STC!");
                                        break;
                              default:
                                        break;
                        }
                        Rec_Flag = 0;
                        //USB_SendData(UsbOutBuffer,OutNumber);
                        usb_OUT_done();
                }
                if(TIME_10MS == 1)
                {
                        TIME_10MS = 0;
                }
      }
} 之前也是一直在使用CDC,不过还是云里雾里的,多应用试试看吧。


第二十三集 看门狗打卡 2024-05-20

1.系统复位方式:上电复位;低压复位;复位脚复位(低电平);看门狗复位。
2.看门狗:是一个计数器,其基本功能是在软件问题和程序跑偏后重启系统,看门狗正常工作时会自动计数,程序进程会定时将其归零。如系统在某个地方卡住或者跑了,定时器就会溢出,系统强制复位。使用有看门狗的芯片时要注意清理看门狗。看门口是独立的计数器,普通的计数器不可代替。
3.看门狗控制寄存器WDT_CONTR:WDT_FLAG溢出标志;EN_WDT使能标志;CLR_WDT定时器清零(喂狗);IDL_WDT,空闲时是否计数;WDT_PS时钟分频系数;
4.实现代码:
void WDT_init(void)//初始化WDT设置
{
      WDT_CONTR = 0x24;//EN_WDT = 1;使能看门狗,WDT_PS=100,分频系数32
}

void WDT_feed(void)//看门狗喂狗
{
      WDT_CONTR = 0x34;//EN_WDT=1,使能看门狗;CLR_WDT=1,看门狗定时器清零;WDT_PS=100,分频系数32
}void main()//程序开始运行的入口
{注意:等待喂狗的时间要大于代码需要执行的时间,留有余量;

第二十四集 比较器打卡 2024-05-21

1.作用:通过比较两端的电压大小,来及时响应某些动作;
2.原理:比较运放的正端电压和负端电压;若V+>V-,输出1,反之为0;
3.比较器初始化函数:
void CMP_init(void)//初始化CMP设置
{
      CMPEXCFG = 0x00;
      CMPEXCFG |= 0xc0;                           //比较器DC迟滞输入选择,0:0mV; 0x40:10mV; 0x80:20mV; 0xc0:30mV(一般选最大)

//CMPEXCFG &= ~0x04;                        //P3.6为CMP-输入脚
      CMPEXCFG |= 0x04;                           //内部1.19V参考电压为CMP-输入脚

      CMPEXCFG &= ~0x03;                        //P3.7为CMP+输入脚
//CMPEXCFG |= 0x01;                           //P5.0为CMP+输入脚
//CMPEXCFG |= 0x02;                           //P5.1为CMP+输入脚
      CMPEXCFG |= 0x03;                           //ADC输入脚为CMP+输入脚


      CMPCR2 = 0x00;
      INVCMPO = 0;                              //比较器正向输出
//INVCMPO = 1;                              //比较器反向输出
      DISFLT = 0;                                 //使能0.1us滤波
//DISFLT = 1;                                 //禁止0.1us滤波
//CMPCR2 &= ~0x3f;                            //比较器结果直接输出
      CMPCR2 |= 0x10;                           //比较器结果经过16个去抖时钟后输出

      CMPCR1 = 0x00;
//PIE = 0;                                    //禁止比较器上升沿中断
      PIE = 1;                                    //使能比较器上升沿中断
//NIE = 0;                                    //禁止比较器下降沿中断
      NIE = 1;                                    //使能比较器下降沿中断

//CMPOE = 0;                                  //禁止比较器输出
      CMPOE = 1;                                  //使能比较器输出

      CMPO_S = 0;                                 //选择P3.4作为比较器输出脚
//CMPO_S = 1;                                 //选择P4.1作为比较器输出脚
      CMPEN = 1;                                  //使能比较器模块
}4.作业:用ADC按键和比较器的方式控制数码管显示当前比较结果,电压大于1.19V显示“On”,否则显示“OFF”;
bit temp = 0;while(1)      //死循环
      {
                delay_ms(2);
                if(bUsbOutReady)
                {
                        //USB_SendData(UsbOutBuffer,OutNumber);
                        usb_OUT_done();
                }
                if(TIME_10MS == 1)
                {
                        TIME_10MS = 0;
                        //ADC_Read(0);
                        if(temp)
                        {
                              SEG0 = 0;   //O
                              SEG1 = 22;//
                              SEG2 = 20;//n
                        }
                        else
                        {
                              SEG0 = 0;   //O
                              SEG1 = 23;//F
                              SEG2 = 23;//F
                        }
                }void CMP_isr() interrupt 21
{
      CMPIF = 0;    //清除中断标志
      if(CMPRES)         //为1,正端电压大于负端电压
      {
                                                                  
      }
      else               //为0,正端电压小于负端电压
      {
               
      }
      temp = CMPRES;   //中断方式读取比较器比较结果
}注意变量定义的位置;


第二十五集 flash模拟EEprom ,跌在坑底躺平了 不知道为什么就是没看懂 , 先接着学之后再回过头来,总要继续的吧,不然就一点事也没得做 ,还是入门级

第二十六集 DS18B20温度传感器打卡2024-05-28~05-30

1.DS18B20简介:数字温度传感器,输出数字信号;单线发送温度信息,三个引脚,正极和负极和DQ脚
2.DS18B20代码过程:


国学芯用 发表于 2024-4-17 13:25:39

咋了,前面发的贴 看不到了吗

好学天上 发表于 2024-4-17 13:38:23

国学芯用 发表于 2024-4-17 13:25
咋了,前面发的贴 看不到了吗

没有啊 只是之前是回复在视频教学帖子下面,工作人员建议我开个新帖记录打卡

好学天上 发表于 2024-4-18 17:00:46

这图片排列这么混乱的吗{:dizzy:}

好学天上 发表于 2024-4-25 15:21:37

怎么又突然冒出bug{:dizzy:}

好学天上 发表于 2024-4-28 15:47:11

原来是因为我没有选择那个图片他就跑到最末尾去了

好学天上 发表于 2024-4-29 11:49:18

哟西粘代码比粘截图好多了,又学到了

小涵子爸爸 发表于 2024-4-29 13:38:23

{:4_250:}

组织小白 发表于 2024-4-29 15:50:19

好学天上 发表于 2024-4-17 13:38
没有啊 只是之前是回复在视频教学帖子下面,工作人员建议我开个新帖记录打卡 ...

我也是搞错了

好学天上 发表于 2024-5-27 09:45:26

eeprom真的没搞懂,改写CDC也没搞清楚,又要跌在坑里躺下了{:cry:}
页: [1]
查看完整版本: STC32G128K芯片学习打卡贴