找回密码
 立即注册
楼主: 未元星系

8H8K64U开天斧开发板学习笔记

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

积分
1619
发表于 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,需要读取全部计次值后才能正常使用,否则计次数量会错乱)
程序代码:(因代码量太大,这里不展示代码了,需要的直接下载文件)



计时器.mp4

8.39 MB, 下载次数: 127

计时器.rar

174.68 KB, 下载次数: 127

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

积分
1619
发表于 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();
        }
}


计时器(EEPROM).mp4

9.69 MB, 下载次数: 129

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

积分
1619
发表于 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);
                }
        }
}




看门狗控制寄存器.png

看门狗-delay(600).mp4

761.74 KB, 下载次数: 131

看门狗-delay(630).mp4

1.31 MB, 下载次数: 137

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

积分
1619
发表于 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;
        }
}

硬件IIC1.png
硬件IIC2.png
硬件IIC3.png
硬件IIC4.png
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

积分
1619
发表于 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();
                }
                //======================================
        }
}


不停电下载(CDC)1.png
不停电下载(CDC)2.png
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:288
  • 最近打卡:2025-05-09 07:30:44

2

主题

52

回帖

914

积分

高级会员

积分
914
发表于 2024-8-7 19:21:17 | 显示全部楼层
学习记录得很好,跟着你的笔记学就可以了
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

积分
1619
发表于 2024-8-7 19:52:25 | 显示全部楼层
tingy*** 发表于 2024-8-7 19:21
学习记录得很好,跟着你的笔记学就可以了

过奖了
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

积分
1619
发表于 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 ;
}



硬件PWM1.png
硬件PWM2.png
硬件PWM3.png
硬件PWM4.png
硬件PWM5.png
硬件PWM6.png
硬件PWM7.png
硬件PWM8.png
硬件PWM9.png
硬件PWM10.png

硬件PWM-呼吸灯.mp4

1.94 MB, 下载次数: 140

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

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


Little_piano.rar

143.78 KB, 下载次数: 135

小电子琴效果演示.mp4

5.64 MB, 下载次数: 146

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:443
  • 最近打卡:2025-05-09 10:10:53
已绑定手机

31

主题

142

回帖

1619

积分

金牌会员

积分
1619
发表于 2024-8-13 21:05:50 | 显示全部楼层

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

51单片机.jpg
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-9 17:18 , Processed in 0.121399 second(s), 104 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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