未元星系 发表于 2024-7-20 18:39:07

本帖最后由 未元星系 于 2024-7-20 18:42 编辑

自学开天斧第16课:
学习内容:定时器详解(三)
学习简介:STC8H8K64U的五个定时器中的T2、T3、T4有八位的预分频寄存器,可以设置预分频从而定时更长的时间,本次学习Timer2做定时器定时1秒。
实验项目:通过定时器2做1s定时,并在中断函数中翻转P3.5口,主函数利用此延时使变量time每秒加一并显示在OLED上;
实验重点:预分频寄存器、STC8H8K64U单片机定时器T2的注意事项
程序代码:
#include <STC8H.H>
#include "OLED.h"

#define ET2 0x04   //定时器2中断开关需要(详情可见开天斧官方例程)

bit Timer2_1s;
unsigned int time;

void Timer2_Init(void)//时钟40M,定时1s
{
      AUXR |= 0x00;//设置定时器2为12T模式
      TM2PS = 0xfa;//设置预分频250
      T2L = 0x55;   //装载初始值52309
      T2H = 0xcc;
      AUXR |= 0x10;//启动定时器
      IE2|=ET2;    //使能T2中断
}

void main()
{      
      P_SW2 |= 0x80;

      P1M0 = 0x00; P1M1 = 0x00;
      P2M0 = 0x00; P2M1 = 0x00;
      P3M0 = 0x00; P3M1 = 0x00;
         
      OLED_Init();//屏幕初始化
      OLED_ColorTurn(0);//0正常显示,1 反色显示
      OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
      OLED_Clear();//清空屏幕

      EA = 1;

      OLED_ShowString(0,2,"Time = ",16);
      OLED_ShowNum(56,2,time,5,16);

      while(1)
      {
                if(Timer2_1s==1)
                {
                        Timer2_1s = 0;
                        time++;
                        OLED_ShowNum(56,2,time,5,16);
                }         
      }
}

void Timer2_Routine(void) interrupt 12
{
      Timer2_1s = 1;
      P35 = ~P35;
}


未元星系 发表于 2024-7-20 22:50:15

本帖最后由 未元星系 于 2024-7-20 22:51 编辑

自学开天斧第17课:
学习内容:定时器详解(四)
学习简介:T3、T4做定时模式输出时钟,并用逻辑分析仪检测。
实验项目:T3做1000HZ输出时钟,T4做500HZ输出时钟。
实验重点:T3/T4功能脚切换
程序代码:
#include <STC8H.H>

void Timer3_Init(void)
{
      T3T4PIN = 0x01;//调整T3、T4时钟输出口分别为P01、P03
      T4T3M &= 0xf0;
      T4T3M |= 0x03;
      T3L = 0xdf;    //定时0.5ms
      T3H = 0xb1;
      T4T3M |= 0x08;
}

void Timer4_Init(void)
{
      T3T4PIN = 0x01;   //调整T3、T4时钟输出口分别为P01、P03
      T4T3M &= 0x0f;
      T4T3M |= 0x30;
      T4L = 0xbf;   ////定时1ms
      T4H = 0x63;
      T4T3M |= 0x80;
}

void main()
{
      P_SW2 |= 0x80;
      
      P0M0 = 0x00; P0M1 = 0x00;

      Timer3_Init();
      Timer4_Init();
      
      while(1){}                  
}

未元星系 发表于 2024-7-21 14:39:57

本帖最后由 未元星系 于 2024-7-21 20:39 编辑

自学开天斧第18课:
学习内容:IO口中断、五向开关
学习简介:①、STC8H8K64U单片机每个IO口均有独立中断,本次以P7口为例学习。
                ②、开天斧板载了一个五向开关的接口(出厂时不带,需自行焊接),连接的五个引脚为P70-P74。
实验重点:①、IO口中断(要点:Keil5无法编译中断号大于31的程序,可通过添加汇编文件中转IO口到13号保留中断)
                ②、五向开关(要点:板载五向开关的板子后面有五颗0欧姆电阻需要一起焊接上,如果没有,也可以直接用焊锡短接)
实验项目:五向开关通过IO口中断控制P2口LED亮灭(按下键翻转P2口、按上键翻转P26口、按下键翻转P20口、按左键翻转24口、按右键翻转P22口)
实验缺陷:中断启动可能受按键抖动影响,需要添加防抖措施(视频中肉眼可见)
程序代码:

#include <STC8H.H>
#include "intrins.h"


void main()
{

      P_SW2 |= 0x80;
               
      P7M0 = 0x00; P7M1 = 0x00;
      P2M0 = 0x00; P2M1 = 0x00;
               
      P7 |= 0x1f;      //P70-P74口为高电平
      
      P7IM0 = 0x00;    //设置P7口中断为下降沿触发
      P7IM1 = 0x00;
      
      P7INTE = 0x1f;//开启P70-P74 口中断
      
      EA = 1;
                        
      while(1){;}
}

void P7_isr(void) interrupt 13
{
      unsigned char intf;
      intf = P7INTF;//获取P7口中断信号
      if(intf)
      {
                P7INTF = 0x00;
               
                if(intf&0x01)//P7.0中键
                {
                  P2 = ~P2;
                }
               
                if(intf&0x02)//P7.1右键
                {
                  P22 = ~P22;
                }
               
                if(intf&0x04)//P7.2左键
                {
                  P24 = ~P24;
                }
               
                if(intf&0x08)//P7.3下键
                {
                  P20 = ~P20;
                }
               
                if(intf&0x10)//P7.4上键
                {
                  P26 = ~P26;
                }
      }
}

//汇编文件内容:

CSEG AT 0163H;将P7口44号中断地址0163H中转到13号中断地址0068H
JMP   006BH
END



jxdaya123 发表于 2024-7-21 17:51:15

加油{:4_250:}

未元星系 发表于 2024-7-21 20:40:57

jxdaya123 发表于 2024-7-21 17:51
加油

嗯嗯{:4_168:}

未元星系 发表于 2024-7-22 23:27:29

今日已开始串口的新一轮学习,虽然遇到各种问题,但也能一一化解,明天会继续学习。

未元星系 发表于 2024-7-23 13:30:11

本帖最后由 未元星系 于 2024-7-23 13:32 编辑

自学开天斧第19课:

学习内容:串口通信详解(一)、定时器扫描独立按键(来自b站江协科技)、STC USB转双串口下载器

学习简介:之前简单了解了UART1向电脑发送和接收数据的功能,本轮计划学习UART2、UART3、UART4的使用

实验重点:①、UART2向电脑收发(printf)数据
                ②、定时器扫描独立按键,按键控制单片机向电脑发送数据
                ③、单片机和电脑通过一箭双雕USB转双串口下载器的第二组串口连接调试(下载器TXD2接P4.7,RXD2接P4.6,使用时注意在串口助手中更换串口号)

实验项目:①、单片机P35口按下,单片机向电脑printf打印一次数据
                ②、电脑串口助手向单片机发送16进制数据,单片机P2口LED随数据亮灭

程序代码:
#include <STC8H.H>
#include <stdio.h>

#define MAIN_Fosc   40000000L
#define BRT (65536 - (MAIN_Fosc / 115200+2) / 4)
bit busy;
bit x;
sbit KEY1 = P3^5;      

unsigned char number1;                              // 测试变量,发送次数 unsigned char 类型
unsigned char str[] = "STC8H8K64U-开天斧3.2";         // 字符串数组
unsigned char Key_KeyNumber;   //独立按键检测

void Timer0_Init(void)                              // 1毫秒@40MHz
{
      AUXR |= 0x80;                                                                // 定时器时钟1T模式
      TMOD &= 0xF0;                                                                // 设置定时器模式
      TL0 = 0xbf;
      TH0 = 0x63;                                                                        // 设置定时初始值
      TF0 = 0;                                                                              // 清除TF0标志
      TR0 = 1;                                                                              // 定时器0开始计时
      ET0 = 1;                                                                              // 使能定时器0中断
}

void Uart2_Init()                                                      // UART2初始化
{

      S2CON = 0x10;                                                                // 模式1(8位数据)、接收使能
      T2L = BRT;                                                
      T2H = BRT >> 8;                                                      // 波特率对应的重装载值
      AUXR |= 0x14;                                                          //打开定时器2(波特率发生器)
      IE2 |= 0x01;                                                                // 使能串口2中断
      P_SW2 |= 0x01;                                                      //设置串口2引脚为P4.6,P4.7
      busy = 0;                                                                        // 清零忙标志
}

void UartPutc(unsigned char dat)                                     //串口发送数据
{
      while(busy);
      busy = 1;
      S2BUF = dat;
}

char putchar(char c)                                                       //重构的putchar函数(需引stdio.h头文件)
{
      UartPutc(c);
      return c;
}

unsigned char Key(void)//返回获取到的按键值
{
      unsigned char Temp=0;
      Temp=Key_KeyNumber;
      Key_KeyNumber=0;
      return Temp;
}

unsigned char Key_GetState(void)//获取按键值
{
      unsigned char KeyNumber=0;
      
      if(P35==0){KeyNumber=1;}
      if(P34==0){KeyNumber=2;}
      if(P33==0){KeyNumber=3;}
      if(P32==0){KeyNumber=4;}

      return KeyNumber;
}

void Timer_Key(void)//定时器循环扫描函数
{
      static unsigned char NowState,LastState;
      LastState=NowState;                              //按键状态更新
      NowState=Key_GetState();                     //获取当前按键状态
                                                               //如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测

      if(LastState==1 && NowState==0){Key_KeyNumber=1;}
      if(LastState==2 && NowState==0){Key_KeyNumber=2;}
      if(LastState==3 && NowState==0){Key_KeyNumber=3;}
      if(LastState==4 && NowState==0){Key_KeyNumber=4;}
}

void main()
{
      unsigned char getkey;
      
      P_SW2 |= 0x80;
      P1M0 = 0x00; P1M1 = 0x00;
      P2M0 = 0x00; P2M1 = 0x00;
      P3M0 = 0x00; P3M1 = 0x00;
      P4M0 = 0x00; P4M1 = 0x00;
      P2 = 0xff;

      EA = 1;                                                                                        // 使能EA总中断
      
      Timer0_Init();
      Uart2_Init();
      
      while(1)
      {                                                                                                                                                
                getkey = Key();
                if(getkey==1)
                {
                        getkey=0;
                        number1++;                                                      // 每次发送后number1+1
                        printf("\n");
                        printf("第%bu次发送\r   ",number1);                        // 发送unsigned char类型
                        printf("%s\r   ",str);                                                // 发送字符串"STC8H8K64U-开天斧三.2"
                        printf("HelloWorld!\r\n\n");                                        // 发送字符串"HelloWorld!"
                }
               
                if(x == 1)
                {
                        x = 0;
                        P2 = ~S2BUF;
                }
      }
}

void Timer0_Routine(void) interrupt 1
{
      static unsigned int T0_count1;
      T0_count1++;
      if(T0_count1>=20){Timer_Key();}//隔20毫秒扫描一次按键状态达到延时效果
      
}

void Uart2_Routine() interrupt 8    //UART2中断
{
      if (S2CON & 0x02)                                                                                        // 发送中断标志置1时
      {
                S2CON &= ~0x02;                                                                        // 清零发送中断标志
                busy = 0;                                                                        // 清零忙状态
      }
      if (S2CON & 0x01)                                                                                        // 接收中断标志置1时
      {
                S2CON &= ~0x01;
                x = 1;
      }
}

未元星系 发表于 2024-7-24 19:24:35

本帖最后由 未元星系 于 2024-7-24 19:29 编辑

自学开天斧第20课:
学习内容:串口通信详解(二):双机通信
学习简介:开天斧开发板 和 STC一箭双雕USB转双串口下载器 主控均为STC8H8K64U单片机,只是封装不同,所以STC双串口下载器也可以看作一个开发板进行代码编写和烧录(按住Download按键后再断一下电源即可进入下载模式),本次用这两个开发板初步学习单片机串口的双机通信
实验重点:①、相关串口的初始化配置(UART2)
                ②、两个开发板的连线(TXD2连RXD2、RXD2连TXD2、GND相连)(备注:双串口下载器的串口引脚丝印与其单片机相反)
                ③、两个开发板烧录同样的代码
                ④、为避免下载器的按键检测与LED和UART2产生干扰,使用自制的独立按键模块(本次实验使用P34引脚,低电平触发)
实验项目:①、开天斧按下P34按键,UART2向双串口下载器发送字符‘1’,下载器P36和P37口LED翻转
                ②、下载器按下P34(检测到低电平),UART2向开天斧发送字符‘1’,开天斧P2口8个LED翻转
程序代码:
#include <STC8H.H>

bit busy;
bit x;

void Delay(unsigned int ms)
{unsigned int i; do{i = MAIN_Fosc / 10000;while(--i);}while(--ms);}

void Uart2_Init()                                                      // UART1初始化
{
      S2CON = 0x10;                                                                // 模式1(8位数据)、接收使能
      T2L = BRT;                                                
      T2H = BRT >> 8;                                                      // 波特率对应的重装载值
      AUXR |= 0x14;
      IE2 |= 0x01;                                                                   // 使能串口1中断
      P_SW2 &= 0xfe;                                                            //设置串口1引脚为P1.0,P1.1
      busy = 0;                                                                      // 清零忙标志
}

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

void main()
{
      P_SW2 |= 0x80;
      P1M0 = 0x00; P1M1 = 0x00;
      P2M0 = 0x00; P2M1 = 0x00;
      P3M0 = 0x08; P3M1 = 0x00;         //P33口配置为推挽模式
      P4M0 = 0x00; P4M1 = 0x00;
      P5M0 = 0x00; P5M1 = 0x00;
      P13 = 1;P14 = 1;P34 = 1;P54 = 0;   //初始化自制独立按键模块
      P33 = 1;                                        //下载器LED供电

      EA = 1;                                                                                        // 使能EA总中断

      Uart2_Init();

      while(1)
      {
               
                if(P34==0)
                {
                        while(P34==0){;}      //为减少代码篇幅,本次使用阻塞延时,上期笔记已介绍定时器扫描按键的延时
                        Delay(20);                //----------------------------------------------------------------------------------------------
                        Uart2Putc('1');
                }
               
                if(x == 1)
                {
                        P36 = ~P36;
                        P37 =~P37;
                        P2 = ~P2;
                        x = 0;
                }
               
      }
}

void Uart2_Routine() interrupt 8
{
      if (S2CON & 0x02)                                                                                        // 发送中断标志置1时
      {
                S2CON &= ~0x02;                                                                        // 清零发送中断标志
                busy = 0;                                                                        // 清零忙状态
      }
      if (S2CON & 0x01)                                                                                        // 接收中断标志置1时
      {
                S2CON &= ~0x01;
                x = 1;
      }
}


未元星系 发表于 2024-7-25 18:33:21

本帖最后由 未元星系 于 2024-7-25 18:35 编辑

自学开天斧第21课:
学习内容:串口通信详解(三):UART3、UART4
学习简介:前两天已学习串口2的使用,串口3和串口4的使用方法与串口2类似,这里只保留UART3、UART4实验成功后的初始化函数和中断函数
程序代码:

bit busy3;
bit busy4;

void Uart3_Init()                                                      // UART3初始化
{
   S3CON = 0x10;       //8位数据, 使用Timer2做波特率发生器, 允许接收
   //S3CON = 0x50;   //8位数据, 使用Timer3做波特率发生器, 允许接收
   T2L = BRT;            
   T2H = BRT >> 8;
   AUXR |= 0x14;   //开启Timer2
   IE2 |= 0x08;      //允许UART3中断
   P_SW2 |= 0x02;   //UART3引脚配置为P0.0 P0.1
   busy3 = 0;                                                                // 清零忙标志

}

void Uart4_Init()                                                      // UART4初始化
{
   S4CON = 0x10;       //8位数据, 使用Timer2做波特率发生器, 允许接收
   T2L = BRT;
   T2H = BRT >> 8;
   AUXR |= 0x14;
   IE2 |= 0x10;      //允许UART4中断
   P_SW2 &= ~0x04;   //UART4 switch bit2 to: 0: P0.2 P0.3
   busy4 = 0;                                                                // 清零忙标志
}

//----------------------------------------------------中断函数--------------------------------------------------//

void Uart3_Routine(void) interrupt 17
{
    if(S3CON & 0x01)      //接收数据
    {
      S3CON &= ~0x01;

    }

    if(S3CON & 0x02)      //发送数据
    {
      S3CON &= ~0x02;
      busy3 = 0;
    }
}

void Uart4_Routine(void) interrupt 18
{
    if(S4CON & 0x01)       //接收数据
    {
      S4CON &= ~0x01;

    }

    if(S4CON & 0x02)      //发送数据
    {
      S4CON &= ~0x02;
      busy4 = 0;
    }
}


未元星系 发表于 2024-7-28 23:08:47

自学开天斧第22课:
学习内容:RTC详解+无源蜂鸣器(定时器控制IO)+OLED显示
学习简介:本次学习STC8H8K64U内部RTC,在OLED上显示时间,启动闹钟,到点蜂鸣器鸣叫
实验项目:①、通过配置RTC在OLED显示时间    ②、设置闹钟,到点开启Timer0输出时钟给无源蜂鸣器IO口提供振动(P35)                ③、开启闹钟中断,到点时蜂鸣器按规律鸣叫(停300ms,叫200ms)
                ④、开启秒中断,每秒P20口LED翻转一次   ⑤、按下P34按键关闭闹钟蜂鸣
实验重点:RTC中断、定时器&无源蜂鸣器
程序代码:
#include <STC8H.H>
#include "OLED.h"

sbit IO_buzzer = P3^5;
sbit VCC_buzzer = P5^1;
sbit GND_buzzer = P3^6;

bit Buzzer_delay;
bit Key_delay;

bit Alarm;

unsigned int Buzzer_off_count;
unsigned int Buzzer_on_count;
unsigned int Key_count;
unsigned char SEC_past;
unsigned char SEC_now;


void Timer0_Init(void)//时钟40M,定时1ms
{
        AUXR |= 0x80;
        TMOD &= 0xF0;
        //TMOD |= 0x04;
        TL0 = 0xbf;
        TH0 = 0x63;
        TF0 = 0;
        TR0 = 1;
        ET0 = 1;
        INTCLKO &= 0xff;
      INTCLKO &= 0xfe;

}



void RTC_Init(void)
{
       
        IRC32KCR = 0x80;         //启动内部低速振荡器
        while(!(IRC32KCR & 0x01)); //等待时钟稳定
        RTCCFG |= 0x02;            //选择内部低速IRC
       
        INIYEAR = 24;            //设置年(00-99)
        INIMONTH = 6;            //设置月(1-12)
        INIDAY = 12;               //设置日(1-31)
        INIHOUR = 18;            //设置时(0-24)   //设置时间:18点23分0秒
        INIMIN = 23;                //设置分(0-60)
        INISEC = 0;               //设置秒(0-60)   
        RTCCFG |= 0x01;            //将设置的时间写入RTC
        RTCIF = 0;               //RTC中断清零
        RTCCR = 0x01;            //启动RTC
       
        RTCIEN |= 0x88;         //使能闹钟中断、秒中断
        ALAHOUR = 18;             //定闹钟为18点23分3秒
        ALAMIN = 23;
        ALASEC = 3;
}


void main()
{

        P_SW2 |= 0x80;
       
        P0M0 = 0x00; P0M1 = 0x00;
        P1M0 = 0x00; P1M1 = 0x00;
        P2M0 = 0x00; P2M1 = 0x00;
        P3M0 = 0x00; P3M1 = 0x00;
        P4M0 = 0x00; P4M1 = 0x00;
        P5M0 = 0x02; P5M1 = 0x00;   //P51配置成推挽输出
      P6M0 = 0x00; P6M1 = 0x00;       
        P34 = 1;
       
        VCC_buzzer = 1; GND_buzzer = 0;

        OLED_Init();
        OLED_ColorTurn(0);//0正常显示,1 反色显示
      OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
        OLED_Clear();


        Timer0_Init();
        RTC_Init();
        EA = 1;


        OLED_ShowString(0,0,"Hello world !",16);
        OLED_ShowChar(34,3,':',16);
        OLED_ShowChar(60,3,':',16);


       
        while(1)
        {
                SEC_past = SEC_now;
                SEC_now= SEC;
                if(SEC_past != SEC_now)
                {
                          OLED_ShowNum(17,3,HOUR,2,16);
                        OLED_ShowNum(43,3,MIN,2,16);
                        OLED_ShowNum(69,3,SEC,2,16);
                }
               
               if(Alarm == 1)
                {
                          if(Buzzer_delay == 1)
                          {
                                    Buzzer_delay = 0;
                                    
                                    if(~(INTCLKO | 0xfe))
                                    {
                                        Buzzer_off_count++;
                                        if(Buzzer_off_count>= 300)//蜂鸣器关闭__ms
                                        {
                                                  Buzzer_off_count = 0;
                                                  INTCLKO |= 0x01;
                                        }
                                    }
                                 
                                    if(INTCLKO & 0x01)
                                    {
                                        Buzzer_on_count++;
                                        if(Buzzer_on_count >= 200)//蜂鸣器开启__ms
                                        {
                                              Buzzer_on_count = 0;
                                                  INTCLKO &= 0xfe;
                                      }
                                    }
                          }
                       
                          if(P34==0)
                        {
                                    if(Key_delay==1)
                                    {
                                                    Key_delay = 0;
                                                    Key_count++;
                                                    if(Key_count >= 20)
                                                    {
                                                              Key_count=0;
                                                              Alarm = 0;
                                                              INTCLKO &= 0xfe;
                                                              VCC_buzzer = 0;
                                                       IO_buzzer = 1;
                                                    }
                                }
                     }
                }
        }
}

void Timer0_Routine(void) interrupt 1
{
        Buzzer_delay = 1;
        Key_delay = 1;
}

void RTC_isp(void) interrupt 13
{
        if(RTCIF & 0x80)
        {
          RTCIF &= ~0x80;
    Alarm = 1;
        }
       
        if(RTCIF & 0x08)
        {
          RTCIF &= ~0x08;
                P20 = ~P20;       
        }
}

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