未元星系 发表于 2024-8-1 18:35:23

本帖最后由 未元星系 于 2024-8-3 15:32 编辑

自学开天斧第23课:
学习内容:小项目(1):计时器(队列存储计次值)
学习简介:通过两个月左右的学习,对这款单片机和开发板有了一定了解,近几天也初步学习了数据结构-队列,本次计划通过完成一个小项目巩固学习过的内容。项目所含知识点:定时器、中断、独立按键、OLED、数据结构-队列项目内容:
①、按P3.5按键 开启/停止计时②、按P3.4按键 清零计时区域数据③、按P3.3按键 计次
④、按P3.2按键 查看计次值(先进先出)实验进步空间:①、EEPROM保存计次数据(尝试了几次都没成功,暂时搁置)②、按P3.5按键 清空计次存储数据+计时区域数据(有bug,需要读取全部计次值后才能正常使用,否则计次数量会错乱)
程序代码:(因代码量太大,这里不展示代码了,需要的直接下载文件)


未元星系 发表于 2024-8-3 15:31:42

自学开天斧第24课:
学习内容:小项目(2):计时器(EEPROM存储计数值)
学习简介:之前对STC8H8K64U的EEPROM的学习只是单纯地存入数据和读出数据,没有结合项目实战,理解不够深入,这次使用EEPROM的库函数制作一个断电存储计次数据的定时器项目所含知识点:GPIO、定时器、中断、独立按键、OLED、EEPROM项目内容:
①、按P3.5按键 开启/停止计时②、按P3.4按键 清零计时区域数据③、按P3.3按键 计次并将数据保存至EEPROM
④、按P3.2按键 查看计次值(读取EEPROM数据)⑤、按P5.4按键 计时器数值、计次值清零,清空存储数据区域(擦除EEPROM第0扇区)程序代码:(因代码量太大,这里只展示主函数,EEPROM相关函数来源于STC库函数)
#include <STC8H.H>
#include "EEPROM.h"
#include "Timer.h"
#include "Timer_Key.h"
#include "OLED.h"

#define Record_MAX 20//存储计次最多数量

bit Timer1_ms_1;
bit Timer1_ms_2;
bit OLED_full_sign;
bit OLED_empty_sign;

unsigned char S_hour;//时
unsigned char S_min;   //分
unsigned char S_sec;   //秒
unsigned char S_cen;   //百分之一秒

unsigned char OLED_past;
unsigned char OLED_know;
unsigned char EEPROM_unit_write;
unsigned char EEPROM_unit_read;
unsigned char Key_number;
unsigned int sign_more_delay;
unsigned int OLED_empty_count;
unsigned int OLED_full_count;
unsigned char Check_empty;

void main()
{
        P_SW2 |= 0x80;
       
        P2M0 = 0x00; P2M1 = 0x00;
        P3M0 = 0x00; P3M1 = 0x00;
      P4M0 = 0x00; P4M1 = 0x00;        
        P5M0 = 0x00; P5M1 = 0x00;
        P6M0 = 0x00; P6M1 = 0x00;
       
      P34 = 1;P35 = 1;P32 = 1;P33 = 1;P54 = 1;//初始化开天斧板载独立按键
       
        Timer0_Init();
        Timer1_Init();
       
        OLED_Init();
        OLED_ColorTurn(0);//0正常显示,1 反色显示
      OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
        OLED_Clear();
       
        TR0 = 0;
        EA = 1;

      OLED_ShowChinese(34,0,0,16);//计
        OLED_ShowChinese(54,0,1,16);//时
        OLED_ShowChinese(74,0,2,16);//器
       
        OLED_ShowNum(7,3,0,2,16);
        OLED_ShowChar(24,3,'h',16);
      OLED_ShowNum(38,3,0,2,16);
        OLED_ShowChar(55,3,'m',16);
        OLED_ShowNum(69,3,0,2,16);
        OLED_ShowChar(86,3,'s',16);
        OLED_ShowNum(100,3,0,2,16);
        OLED_ShowString(117,3,"c",16);
       
        OLED_ShowChinese(0,6,6,16);
        OLED_ShowChar(17,6,':',16);
      OLED_ShowNum(24,6,0,2,16);

        while(1)
        {
                Key_number = Key();
               
                OLED_past = OLED_know;
                OLED_know = S_cen;
               
                if(OLED_past != OLED_know)//if计时变量改变刷新OLED
                {
                        OLED_ShowNum(7,3,S_hour,2,16);
                        OLED_ShowNum(38,3,S_min,2,16);
                      OLED_ShowNum(69,3,S_sec,2,16);   
                      OLED_ShowNum(100,3,S_cen,2,16);
                }
               
                if(Key_number == 1)//开启/关闭计时器
                {
                  TR0 = ~TR0;
                        if(TR0 == 0)
                        {
                          sign_more_delay = 200;
                        }
                        else
                        {
                          sign_more_delay = 0;
                        }
                }
               
                if(Key_number == 2)//计时器清零
                {
                  S_cen = 0;S_sec = 0;S_min = 0;S_hour = 0;
                }
               
                if(Key_number == 3)//计时器计次
                {

                        OLED_ShowChinese(0,6,6,16);
                        OLED_ShowChar(17,6,':',16);
                       
                        if(EEPROM_unit_write >= Record_MAX)//如果EEPROM_unit_write大于等于设定值,显示“满!”
                        {
                          OLED_ShowChinese(86,6,3,16);
                        OLED_ShowChinese(103,6,5,16);
                        OLED_full_sign = 1;
                        }
                        else
                        {
                                OLED_ShowNum(24,6,EEPROM_unit_write+1,2,16);
                                EEPROM_write_n(0x0000+1+EEPROM_unit_write*4,&S_hour,1);
                                EEPROM_write_n(0x0000+2+EEPROM_unit_write*4,&S_min,1);
                                EEPROM_write_n(0x0000+3+EEPROM_unit_write*4,&S_sec,1);
                                EEPROM_write_n(0x0000+4+EEPROM_unit_write*4,&S_cen,1);
                              EEPROM_unit_write++;
                        }
                }
               
                if(Key_number == 4)//计时器显示计次值
                {
                        OLED_ShowChinese(0,6,7,16);
                        OLED_ShowChar(17,6,':',16);
                        EEPROM_read_n(0x0000+4+EEPROM_unit_read*4,&Check_empty,1);

                        if(Check_empty == 0xff )//如果EEPROM下一字节是被擦除状态(0xff),显示“空!”
                        {
                          OLED_ShowChinese(86,6,4,16);//显示“空!”
                                OLED_ShowChinese(103,6,5,16);
                                OLED_empty_sign = 1;
                        }
                        else
                        {
                                EEPROM_read_n(0x0000+1+EEPROM_unit_read*4,&S_hour,1);//读取EEPROM数据
                                EEPROM_read_n(0x0000+2+EEPROM_unit_read*4,&S_min,1);
                                EEPROM_read_n(0x0000+3+EEPROM_unit_read*4,&S_sec,1);
                                EEPROM_read_n(0x0000+4+EEPROM_unit_read*4,&S_cen,1);
                               
                                OLED_ShowNum(7,3,S_hour,2,16);//显示数据
                              OLED_ShowNum(38,3,S_min,2,16);
                                OLED_ShowNum(69,3,S_sec,2,16);
                                OLED_ShowNum(100,3,S_cen,2,16);
                                OLED_ShowNum(24,6,EEPROM_unit_read+1,2,16);
                               
                                EEPROM_unit_read++;
                        }
                }
               
                if(Key_number == 5)
                {
                        EEPROM_SectorErase(0x0000);
                        EEPROM_unit_read = 0;
                        EEPROM_unit_write = 0;
                        S_cen = 0;S_sec = 0;S_min = 0;S_hour = 0;
                        OLED_ShowNum(24,6,EEPROM_unit_write,2,16);
                }
               
                if(OLED_empty_sign == 1)
                {
                  if(Timer1_ms_1 == 1)
                        {
                          Timer1_ms_1 = 0;
                                OLED_empty_count++;
                                if(OLED_empty_count >= 150+sign_more_delay)
                                {
                                        OLED_empty_count = 0;
                                        OLED_empty_sign = 0;
                                        OLED_ShowString(86,6,"   ",16);
                                }
                        }
                }
               
                if(OLED_full_sign == 1)
                {
                        if(Timer1_ms_2 == 1)
                        {
                                Timer1_ms_2 = 0;
                                OLED_full_count++;
                                if(OLED_full_count >= 150+sign_more_delay)
                                {
                                        OLED_full_count = 0;
                                        OLED_full_sign = 0;
                                        OLED_ShowString(86,6,"   ",16);
                                }
                        }
                }
        }
}


void Timer0_Routine(void) interrupt 1
{
        static unsigned char Timer0_cen;//定时器循环计时
        Timer0_cen++;
       
      if(Timer0_cen >= 10){Timer0_cen = 0;S_cen++;}
        if(S_cen >= 100){S_cen = 0;S_sec++;}
      if(S_sec >= 60){S_sec = 0;S_min++;}
        if(S_min >= 60){S_min = 0;S_hour++;}
}

void Timer1_Routine(void) interrupt 3
{
        static unsigned char T0_Key;
        T0_Key++;
        Timer1_ms_1 = 1;
        Timer1_ms_2 = 1;
       
        if(T0_Key>=20)
        {
                T0_Key = 0;
                Timer_Key();
        }
}

未元星系 发表于 2024-8-3 21:44:56


自学开天斧第25课:
学习内容:看门狗
学习简介:单片机的看门狗可以有效预防单片机程序跑飞,死机的情况,通过设定看门狗控制寄存器使用,若看门狗定时器溢出前没有按时喂狗,单片机会自动复位。代码内容:看门狗定时0.629秒,变量num delay 600ms加一,程序正常显示,将delay值变为630ms后单片机循环复位,OLED不显示变量num的变化程序代码:#include <STC8H.H>#include "OLED.h"
#define MAIN_Fosc 40000000L
unsigned char num;unsigned char num_past;unsigned char num_now;
void main(){        num = 10;        P_SW2 |= 0x80;        P2M0 = 0x00; P2M1 = 0x00;                 OLED_Init();      OLED_ColorTurn(0);      OLED_DisplayTurn(0);        OLED_Clear();        OLED_ShowNum(0,0,num,3,16);                        WDT_CONTR = 0x25;//0.629秒
        while(1)        {                Delay_ms(600);//630                WDT_CONTR = 0x35;//0.629秒喂狗                num++;                num_past = num_now;                num_now = num;                if(num_now != num_past)                {                   OLED_ShowNum(0,0,num,3,16);                }        }}




未元星系 发表于 2024-8-4 20:08:35

本帖最后由 未元星系 于 2024-8-4 20:09 编辑

自学开天斧第26课:
学习内容:硬件I2C
学习简介:STC8H8K64U单片机内置一个I2C总线控制器,相较于软件I2C速度更快,可以减轻CPU负担代码内容:OLED 硬件I2C 起始、等待应答、发送一字节数据、停止相关函数程序代码:bit busy_hI2C;
void I2C_Start(void)//起始信号{      busy_hI2C = 1;      I2CMSCR = 0x81;      while(busy_hI2C);
}
void I2C_Stop(void)//结束信号{busy_hI2C = 1;      I2CMSCR = 0x86;      while(busy_hI2C);}
void I2C_WaitAck(void) //等待信号响应{      busy_hI2C = 1;      I2CMSCR = 0x83;      while(busy_hI2C);}
void Send_Byte(unsigned char dat)//写入一个字节{      I2CTXD = dat;      busy_hI2C = 1;      I2CMSCR = 0x82;      while(busy_hI2C);}
//中断函数:void I2C_isr(void) interrupt 24{if(I2CMSST & 0x40)        {          I2CMSST &= ~0x40;                busy_hI2C = 0;        }}

未元星系 发表于 2024-8-5 23:05:25

自学开天斧第27课:
学习内容:不停电下载(CDC)
学习简介:开天斧开发板下载时需要按P3.2按键再按off按键,比较麻烦,如果想更简便一般需要用下载器。不过STC8H8K64U有不使用下载器同时不断电的方法下载程序,这里介绍CDC的方案。代码内容:OLED按频率闪烁学习重点:需要引入stc32_stc8_usb.h 头文件 ,包含stc_usb_cdc_8h_data.lib 文件在项目中。文件可以在STC-ISP中的“资料下载”中下载。代码现象:不使用烧录器,第一次烧录仍需要按按键断电,第二次开始,只需电脑鼠标操作下载即可自动将程序烧录进单片机,无需断电。程序代码#include <STC8H.H>#include "stc32_stc8_usb.h"//引入头文件
#define MAIN_Fosc 40000000L
//============================//不停电下载(CDC)固定格式char *USER_DEVICEDESC = NULL;char *USER_PRODUCTDESC = NULL;char *USER_STCISPCMD = "@STCISP#";//============================
void Delay_ms(unsigned int ms){        unsigned int i;        do{                i = MAIN_Fosc / 10000;                while(--i);        }while(--ms);}
void main(){        P_SW2 |= 0x80;        P2M0 = 0x00; P2M1 = 0x00;                 //=============================//不停电下载(CDC)固定格式        P3M0 &= ~0x03; P3M1 |= 0x03;        IRC48MCR = 0x80;        while(!(IRC48MCR & 0x01));        USBCLK = 0x00;        USBCON = 0x90;        usb_init();        IE2 |= 0x80;        //=============================                EA = 1;                while(1)        {                P2 = ~P2;                Delay_ms(500);                P2 = ~P2;                Delay_ms(500);                                //======================================//不停电下载(CDC)固定格式                if(bUsbOutReady)                {                  USB_SendData(UsbOutBuffer,OutNumber);                        usb_OUT_done();                }                //======================================        }}

tingyu8675 发表于 2024-8-7 19:21:17

学习记录得很好,跟着你的笔记学就可以了

未元星系 发表于 2024-8-7 19:52:25

tingyu8675 发表于 2024-8-7 19:21
学习记录得很好,跟着你的笔记学就可以了

过奖了{:4_196:}

未元星系 发表于 2024-8-8 10:08:30


自学开天斧第28课:
学习内容:硬件PWM
学习简介:STC8H8K64U单片机集成了8通道16位高级PWM定时器,第一组四个通道可独立实现PWM输出(可设置带死区的互补对称输出)、捕获、比较功能;第二组四个通道可独立实现PWM输出、捕获、比较功能;功能强大但内容复杂,本次学习PWM1P的输出代码内容:PWM1P配置输出引脚为P2.0,输出周期为10ms,占空比在0%-100%范围按每毫秒0.1%的速度递增或递减,实现P2.0口LED表现呼吸灯。学习重点:硬件PWM寄存器的设置代码现象:P2.0口LED,呼吸灯,周期2s。程序代码:#include <STC8H.H>#include "Timer-all.h"#include "stc32_stc8_usb.h"
//============================//不停电下载(CDC)固定格式char *USER_DEVICEDESC = NULL;char *USER_PRODUCTDESC = NULL;char *USER_STCISPCMD = "@STCISP#";//============================
unsigned int Cycle_1;unsigned int Duty_1;
bit PWM1_Flag;
void main(){        P_SW2 |= 0x80;        P1M0 = 0x00;P1M1 = 0x00;        P2M0 = 0x00;P2M1 = 0x00;              //=============================//不停电下载(CDC)固定格式      P3M0 &= ~0x03; P3M1 |= 0x03;      IRC48MCR = 0x80;      while(!(IRC48MCR & 0x01));      USBCLK = 0x00;      USBCON = 0x90;      usb_init();      IE2 |= 0x80;      //=============================                Timer0_Init();        EA = 1;                Cycle_1 = 1000;//周期:1ms        Duty_1 = 0;//占空比:50%                PWMA_PS |= 0x01;//设置PWM通道1输出引脚为P20、P21                PWMA_CCER1 = 0x00;//清零PWMA_CCER1寄存器        PWMA_CCMR1 = 0x60;//选择PWM模式1        PWMA_CCER1 = 0X01; //开启输入捕获/比较输出
        PWMA_PSCRH = (40-1) >> 8;//预分频(系统时钟40M)        PWMA_PSCRL = (40-1);                PWMA_ARRH = Cycle_1 >> 8;//设置周期        PWMA_ARRL = Cycle_1;              PWMA_CCR1H = Duty_1>> 8;//设置占空比        PWMA_CCR1L = Duty_1 ;              PWMA_ENO = 0X01;//使能PWM1P输出      PWMA_BKR = 0X80;//使能主输出      PWMA_CR1 = 0X01;        //使能PWM计数器
        while(1)        {
               //======================================//不停电下载(CDC)固定格式               if(bUsbOutReady)               {                        USB_SendData(UsbOutBuffer,OutNumber);                        usb_OUT_done();               }                //======================================

      }}
void Timer0_Routine(void) interrupt 1{      if(!PWM1_Flag)   {         Duty_1 ++;         if(Duty_1 > Cycle_1) PWM1_Flag = 1;   }   else   {         Duty_1 --;         if(Duty_1 <= 0) PWM1_Flag = 0;   }   PWMA_CCR1H = Duty_1>> 8;//设置占空比   PWMA_CCR1L = Duty_1 ;}



未元星系 发表于 2024-8-10 20:50:31

自学开天斧第29课:
学习内容:小项目(三):小电子琴
学习简介:通过此项目学习单片机定时器和各电子模块的组合使用。代码内容:定义音调低音5--高音相应频率的定时器装载值数组(16个音),通过矩阵键盘模块控制选择装载值,蜂鸣器模块按选中的音调频率发音,同时OLED模块实时显示当前按下的音调值。(定时器设为十六位不自动重装模式)学习重点:定时器、矩阵键盘模块、蜂鸣器模块、OLED模块代码现象:矩阵键盘控制蜂鸣器按相应音调鸣叫,OLED显示当前音调值。

未元星系 发表于 2024-8-13 21:05:50


      对于开天斧开发板的学习笔记暂时就记录到这里,历时两个多月,经过两轮学习,对8H8K64U这款芯片整体上有了初步认识,收获很大,这个暑假过的十分充实。
感谢官方提供的技术论坛,能够让我寻找各种资料,记录学习;感谢论坛和交流群里每一位予以指点的大佬,帮助我克服困难;最后,也感谢那个一路坚持学习的自己。
同时,我对51单片机的学习不会就此完结,我会在后期初步学习电路设计后尝试做真正的单片机项目,到那时,我会继续记录我的单片机学习旅程,加油!

页: 1 2 3 4 5 [6] 7
查看完整版本: 8H8K64U开天斧开发板学习笔记