未元星系 发表于 2024-5-27 22:57:59

本帖最后由 未元星系 于 2024-5-27 22:59 编辑

自学开天斧第⑤课:
学习内容:1、外部中断
学习简介:STC8H8K64U单片机内置五个外部中断,INT0,INT1,INT2,INT3,INT4;分别对应引脚:P3.2,P3.3,P3.6,P3.7,P3.0;分别对应中断号:interrupt 0,2,10,11,16;

其中INT0和INT1即支持上升沿/下降沿中断(同时支持两种方式引发中断),也支持下降沿中断,INT2,INT3,INT4只支持下降沿中断。
外部INT0,INT1所连引脚正好为两个独立按键,本次实验:主函数执行死循环,设INT0,INT1为下降沿触发,若P3.3按键按下,LED交替闪烁两回合;若P3.2按下,LED闪烁两次
程序代码:

#define MAIN_Fosc                24000000L      
void Delay_ms(unsigned int ms)
{
      unsigned int i;
      do{
                i = MAIN_Fosc / 10000;
                while(--i);
      }while(--ms);
}

void main()
{
      
      P2M0 = 0x00; P2M1 = 0x00;   //P2口设为准双向口模式
      P3M0 = 0x00; P3M1 = 0x00;   //P3口设为准双向口模式
P2 = 0xff;                  //熄灭全部LED
      P2 |= 0x30;               //P3.2, P3.3口设为高电平
      
      IT0 = 1;                  //外部中断0设置为下降沿触发(若IT0=1则设置为上升沿+下降沿触发)
      EX0 = 1;                  //使能INT0
      IT1 = 1;                  //外部中断1设置为下降沿触发(若IT1=1则设置为上升沿+下降沿触发)
      EX1 = 1;                  //使能INT1
      
      EA = 1;                                  //打开总中断
      
      while(1){}                  //死循环
}

void INT0_Routine(void)interrupt 0
{
    P2 = 0x55;Delay_ms(150);
    P2 = 0xAA;Delay_ms(150);
    P2 = 0x55;Delay_ms(150);
    P2 = 0xAA;Delay_ms(150);
    P2 = 0xff;
}

void INT1_Routine(void)interrupt 2
{
   P2 = 0x00;Delay_ms(100);
   P2 = 0xff;Delay_ms(100);
   P2 = 0x00;Delay_ms(100);
   P2 = 0xff;Delay_ms(100);
}


代码现象:P3.3按键按下,LED交替闪烁两回合;P3.2按下,LED闪烁两次
存在问题:按键按下会产生抖动,目前外部中断里的消抖本人目前也没完全弄明白,所以此程序可能会导致按一下按键触发多次中断的现象。

未元星系 发表于 2024-5-28 23:23:29

本帖最后由 未元星系 于 2024-5-28 23:26 编辑

自学开天斧第⑥课:
学习内容:1、定时器延时
学习简介:前期我学习的延时函数是严重占用单片机进程的,实际编程中不是十分提倡,今天开始学习定时器延时。
实验内容:用定时器0进行延时,流水灯
程序代码:
bit bit_1ms;
unsigned int delay;

void Timer0_Init(void)//定时1ms
{
      AUXR |= 0x80;//设置定时器为1T模式,即不分频
      TMOD &= 0xF0;//保留高四位(定时器1),低四位全为0:设置定时器/计数器0为定时器、GATE置0、16位自动重装模式
      TL0 = 0x3F;         //初始值65535 - 24000 = 41535 = 1010 0010 0011 1111,即高8位为0xA2,低8位为0x3F
      TH0 = 0xA2;         //
      TF0 = 0;                  //清零TF0中断标志位
      TR0 = 1;                  //定时器开始计时
      ET0 = 1;       //开启定时器0中断
}

void main()
{
      P2M0 = 0x00; P2M1 = 0x00;   //P2口设为准双向口模式
       Timer0_Init();
       EA = 1;                                  //打开总中断

      while(1)
      {
                static unsigned char j;
                if(bit_1ms == 1)
                {
                        bit_1ms = 0;
                        delay++;
                }
                if(delay >= 100)//流水灯流动速度:100ms
                {
                        delay = 0;
                        P2 = ~(0x01 << j);
                        j ++ ;
                        if(j > 7){j = 0;}
               }
               
       }               
}

void Timer0_Routine(void) interrupt 1   //定时器0中断
{
      bit_1ms = 1;//设置标志位,bit_1ms清零后置1说明时间过了1ms
}

代码现象:循环流水灯,速度100ms

未元星系 发表于 2024-5-31 22:08:13

本帖最后由 未元星系 于 2024-5-31 23:11 编辑

自学开天斧第⑦课:
学习内容:1、串口通信
学习简介:STC8H8K64U单片机有四个串口,都为全双工异步串行通信接口,串口1有四种工作模式,串口2、3、4有两种(本次学习串口1的模式1),串口1可切换4组引脚,串口2、3、4能切换2组
实验项目:1.单片机向电脑发送数据:开天斧4个板载按键,按下分别向电脑发送 “你好呀!”“很高兴认识你!”“祝你好运!”“再见!”
                2.电脑向单片机发送数据:STC-ISP串口助手向单片机发送16进制数,8个板载LED按照2进制点亮(注意将串口发送调为HEX模式)
程序代码:
#define MAIN_Fosc   24000000L
sbit KEY1 = P3^2; sbit KEY2 = P3^3; sbit KEY3 = P3^4; sbit KEY4 = P3^5;      // 板载的4个按键
bit B_1ms;         // 1毫秒标志
bit key1flag; bit key2flag; bit key3flag; bit key4flag;         // 按键1按下标志
bit blinkflag;                        // 闪烁标志
bit busy;   //忙状态
char key1delay;      char key2delay;      char key3delay;      char key4delay;            // 4个按键计时

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

void Uart1Init()                                                      // UART1初始化
{
      P_SW1 &= 0x3F;            //设置串口1引脚为P3.0,P3.1
      SCON = 0x50;                                                                // 模式1(8位数据)、接收使能
      PCON |= 0x00;               //设置波特率不加倍,关闭帧错检测功能
      T2L = BRT;                                                
      T2H = BRT >> 8;                                                      // 波特率对应的重装载值
      AUXR |= 0x15;                                                         // 定时器2做波特率发生器    1T模式   启动定时器2
      busy = 0;                                                                              // 清零忙标志
}
void UartSend(char dat)                              // 发送字符函数
{
      while (busy);                                                                // 当串口忙时,等待
      busy = 1;                                                                              // 忙标志置1
      SBUF = dat;                                                                        // 发送数据dat
}
void UartSendStr(char *p)                        // 发送字符串函数
{while (*p)      {UartSend(*p++);}}                        // 逐个发送字符串的字符

void main()
{
      
      P2M0 = 0x00; P2M1 = 0x00;
      P3M0 = 0x00; P3M1 = 0x00;
      P2 = 0xff; P3 = 0xff;

      Timer0_Init();                                                      // 定时器0初始化
      Uart1Init();                                                                // 串口1初始化
      ES = 1;                                                                                        // 使能串口1中断
      EA = 1;                                                                                        // 使能EA总中断
      
      while (1)
      {
                if(KEY1 == 0)                                                                                                                // P3.2按键按下
                {
                        if(key1flag == 0)                                                                                        // 当按下标志为0时
                        {                                                                                                                                                      
                              if(B_1ms == 1) key1delay++;                                        // 按键延时,每1毫秒+1
                              if(key1delay >=10)                                                                        // 按下时间大于10毫秒
                              {key1delay = 0;key1flag = 1;UartSendStr("你好呀!\r\n");}                // 清零按键延时按下标志置1发送字符串“你好呀!”
                        }
                }
                if(KEY1 == 1){key1flag = 0;key1delay = 0;}         // 按键松开清零按键按下标志清零按键延时
                                                               
               
               
                if(KEY2 == 0)                                                                                                                // P3.3按键按下
                {
                        if(key2flag == 0)                                                                                        // 当按下标志为0时
                        {                                                                                                                                                      
                              if(B_1ms == 1) key2delay++;                                        // 按键延时,每1毫秒+1
                              if(key2delay >=10)                                                                        // 按下时间大于10毫秒
                              {key2delay = 0;key2flag = 1;UartSendStr("很高兴认识你!\n");}                // 清零按键延时按下标志置1发送字符串“很高兴认识你!”
                        }
                }
                if(KEY2 == 1){key2flag = 0;key2delay = 0;}         // 按键松开清零按键按下标志清零按键延时
               
               
               
                if(KEY3 == 0)                                                                                                                // P3.3按键按下
                {
                        if(key3flag == 0)                                                                                        // 当按下标志为0时
                        {                                                                                                                                                      
                              if(B_1ms == 1) key3delay++;                                        // 按键延时,每1毫秒+1
                              if(key3delay >=10)                                                                        // 按下时间大于10毫秒
                              {key3delay = 0;key3flag = 1;UartSendStr("祝你好运!\n");}                // 清零按键延时按下标志置1发送字符串“祝你好运!”
                        }
                }
                if(KEY3 == 1){key3flag = 0;key3delay = 0;}         // 按键松开清零按键按下标志清零按键延时
               
               
               
                if(KEY4 == 0)                                                                                                                // P3.3按键按下
                {
                        if(key4flag == 0)                                                                                        // 当按下标志为0时
                        {                                                                                                                                                      
                              if(B_1ms == 1) key4delay++;                                        // 按键延时,每1毫秒+1
                              if(key4delay >=10)                                                                        // 按下时间大于10毫秒
                              {key4delay = 0;key4flag = 1;UartSendStr("再见!\n");}                // 清零按键延时按下标志置1发送字符串“再见!”
                        }
                }
                if(KEY4 == 1){key4flag = 0;key4delay = 0;}         // 按键松开清零按键按下标志清零按键延时

}

void Timer0_Isr(void) interrupt 1
{
      B_1ms = 1;                                                                        // 1毫秒标志
}

void Uart1Isr() interrupt 4
{
      if (TI == 1)                                                                                        // 发送中断标志置1时
      {
                TI = 0;                                                                              // 清零发送中断标志
                busy = 0;                                                                        // 清零忙状态
      }
      if (RI == 1)                                                                                        // 接收中断标志置1时
      {
                RI = 0;
                P2 = ~SBUF;                                                                //P2口赋值SBUF取反结果

      }
}



未元星系 发表于 2024-6-1 20:23:37

本帖最后由 未元星系 于 2024-6-1 20:25 编辑

自学开天斧第⑧课:
学习内容:1、掉电模式(也叫省电模式/停电模式/主时钟停振)2、空闲模式
学习简介:STC8H8K64U单片机有两种低功耗模式:掉电模式和空闲模式。
                1、掉电模式:CPU和外设都停止工作。   2、空闲模式:CPU停止工作,外设正常运行。
                掉电模式可以通过定时器、中断、串口、比较器中断、低压检测中断、掉电唤醒定时器、I2C等方式唤醒
                使用低功耗模式需要调用电源控制寄存器PCON
实验项目:1.单片机一遍流水灯后进入掉电/空闲模式,P3.2口外部中断唤醒继续一边流水灯,再次进入掉电/空闲模式,循环这个过程。
程序代码:
#include <STC8H.H>
#define MAIN_Fosc24000000L


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

void main()
{
      unsigned char i;
      unsigned char a = 0x01;
      P2M0 = 0x00; P2M1 = 0x00;
      P3M0 = 0x00; P3M1 = 0xc3;
      P2 = 0x01;
      
      IT0 = 1;                  //外部中断0设置为下降沿触发
      EX0 = 1;                  //使能INT0
      EA = 1;                     //打开总中断
      
      while(1)
      {
               for(i = 0;i < 8;i++)
               {
                         P2 = ~(a << i);
                         Delay_ms(100);
                         P2 = 0xff;
               }
               PCON |= 0x02;//开启掉电模式/ |= 0x01为省电模式
      }
}

void INT0_Routine(void)   interrupt 0
{}




未元星系 发表于 2024-6-2 23:35:58

本帖最后由 未元星系 于 2024-6-2 23:41 编辑

自学开天斧第⑨课:
学习内容:1、printf函数串口打印
学习简介:我们初学C语言的第一课通常是printf打印"Hello World!",STC8H8K64U单片机也可以调用printf函数,将信息打印在串口助手里,使用这一功能需要以下操作:
                1、添加#inculde <stdio.h>头文件
                2、配置串口
                3、重构putchar函数
                4、调用printf函数
实验项目:单片机每隔1秒在串口助手打印一次数据;串口助手向单片机发送数据时,P2口LED按数据2进制亮灭。
程序代码:


#include <STC8H.H>
#include <stdio.h>

#define MAIN_Fosc   24000000L
#define BRT (65536 - (MAIN_Fosc / 115200+2) / 4)

bit busy;
bit B_1ms;                                                                              // 1毫秒标志
bit x;                                                                              //串口接收标志
sbit KEY1 = P3^5;      

int delay;                                                                  // 计时
unsigned char number1;                              // 测试变量,发送次数 unsigned char 类型
char number2;                                                                        // 测试变量,char 类型
unsigned int humidi;                                        // 测试变量,unsigned int 类型
int temper1;                                                                        // 测试变量,int类型
int temper2;                                                                        // 测量变量,int类型
float temper3;                                                                // 测试变量,float类型
float temper4;                                                                // 测试变量,float类型
unsigned char str[] = "STC8H8K64U-开天斧3.2";         // 字符串数组

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

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

void Uart1Init()                                                      // UART1初始化
{
      P_SW1 &= 0x3F;            //设置串口1引脚为P3.0,P3.1
      SCON = 0x50;                                                                // 模式1(8位数据)、接收使能
      PCON |= 0x00;               //设置波特率不加倍,关闭帧错检测功能
      T2L = BRT;                                                
      T2H = BRT >> 8;                                                      // 波特率对应的重装载值
      AUXR |= 0x15;
      busy = 0;                                                                              // 清零忙标志
}

void UartPutc(unsigned char dat)
{
      busy = 1;
      SBUF = dat;
      while(!TI);
      TI = 0;
      busy = 0;
}

char putchar(char c)                                                      //重构putchar函数
{
      UartPutc(c);
      return c;
}

void main()
{
      P2M0 = 0x00; P2M1 = 0x00;
      P3M0 = 0x00; P3M1 = 0x00;
      P2 = 0xff; P3 = 0xff;
      ES = 1;                                                                                        // 使能串口1中断
      EA = 1;                                                                                        // 使能EA总中断
      
      Timer0_Init();
      Uart1Init();
      
      temper1 = 25;                                                                // 测试变量,温度1 = 25度            int类型,正数
      temper2 = -2;                                                                // 测试变量,温度2 = -2度                        int类型,负数
      temper3 = 25.6;                                                      // 测试变量,温度3 = 25.6度                float类型,正数
      temper4 = -2.5;                                                      // 测试变量,温度4 = -2.5度                float类型,负数
      humidi = 50;                                                                // 测试变量,湿度= 50 %                        unsigned int类型
      
      while(1)
      {                                                                                                                                                
                              if(B_1ms == 1)                              // 1毫秒到
                              {      
                                        B_1ms = 0;                                        // 清零1毫秒标志
                                        delay++;                              // 按键延时,每1毫秒+1
                              }                                       
                              if(delay >= 1000)                // 按下时间大于1000毫秒
                              {
                                        delay = 0;                        // 清零按键延时
                                        number1++;                                                                                                      // 每次发送后number1+1
                                        number2++;                                                                                                      // 每次发送后number2+1
          // Keil 扩展了 b h l,对应字节宽度,b-8位,h-16位(默认),l-32位
          // printf中有符号对应 %d,无符号对应%u 或 %x, 浮点型:%f,字符串 %s
          // u8对应 %bu 或 %bx,      char 对应 %bd
          // u16 对应 %hu      或 %hx,      int对应 %d 或 %hd
          // u32 对应 %lu 或 %lx,long 对应 %ld
                                        printf("\n");
                                        printf("第%bu次发送\r   ",number1);      // 发送unsigned char类型,number1是u8类型,需要使用 %bu 或 %bx
                                        printf("第%bd次打印\r   ",number2);      // 发送 char类型,number2是 char类型,需要使用 %bd
                                        printf("湿度:%hu%%\r   ",humidi);                // 发送unsigned int类型,humidi是 u16 类型,需要使用 %hu 或 %hx
                                        printf("温度1:%hd℃\r   ",temper1);                        // 发送int 类型,temper是 int类型,需要使用 %hd
                                        printf("温度2:%hd℃\r   ",temper2);                        // 发送int 类型,temper是 int 类型,需要使用 %hd
                                        printf("温度3:%4.1f℃\r   ",temper3);                              // 发送float类型,temper是 int 类型,需要使用 %f,2位整数,1位小数 %4.1f
                                        printf("温度4:%3.1f℃\r\n",temper4);                // 发送 float类型,temper是 int类型,需要使用 %f,1位整数,1位小数 %3.1f
                                        printf("%s\r   ",str);                                                                // 发送字符串"STC8H8K64U-开天斧三.2"
                                        printf("HelloWorld!\r\n\n");                                        // 发送字符串"HelloWorld!"
                              }
               
                if(x == 1)
                {
                        x = 0;
                        P2 = ~SBUF;
                }
               
      }
}

void Timer0_Routine(void) interrupt 1
{
      B_1ms = 1;                                                                        // 1毫秒标志
}

void Uart1Isr() interrupt 4
{
      if (TI == 1)                                                                                        // 发送中断标志置1时
      {
                TI = 0;                                                                              // 清零发送中断标志
                busy = 0;                                                                        // 清零忙状态
      }
      if (RI == 1)                                                                                        // 接收中断标志置1时
      {
                RI = 0;
                x = 1;
      }
}

(备注:视频演示发送的串口数据中,湿度出了错误,原因是一开始定义湿度取成了char类型,printf引用为int型,代码已纠正。)



soma 发表于 2024-6-3 11:34:36

学的真好

未元星系 发表于 2024-6-3 11:52:59

zhaoye818 发表于 2024-6-3 07:55


{:4_196:}{:4_196:}

未元星系 发表于 2024-6-3 11:53:32

soma 发表于 2024-6-3 11:34
学的真好

感谢认可,会继续坚持学习{:4_196:}

未元星系 发表于 2024-6-3 23:10:49

2024年6月3日,今天计划学习串口DMA发送与接收,DMA发送实验成功,但DMA接收代码仍有错误,暂未找出原因,明日继续学习。

vb2002 发表于 2024-6-4 00:58:54

为什么你学的这么快,我学的那么慢啊
页: 1 [2] 3 4 5 6 7
查看完整版本: 8H8K64U开天斧开发板学习笔记