找回密码
 立即注册
楼主: CListery

跟着冲哥学习单片机

[复制链接]
  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-7-1 17:23:33 | 显示全部楼层
本帖最后由 CListery 于 2024-7-9 10:28 编辑

第十八课:
1. 代码可以根据功能分成多个文件,按名称划分,如 xxx.h 和 xxx.c 相对应
2. 通过Keil 的 include path 功能将路径引入
3. 通过 extern 关键字可以将变量暴露出去,让其他源文件使用变量
4. 通过 static 关键字可以在函数中声明一个只初始化一次的变量,后续再次进入函数将会使用最后一次的值
复习心得:
1. 重点关注关键字的不同
在.h中声明变量
extern u8 bdata LED_STATES;
extern bit LED0;
extern bit LED_SW;
在.c中定义变量
u8 bdata LED_STATES= 0xFF;
sbit LED0 = LED_STATES^0;
sbit LED_SW = P4^0;

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-7-1 17:25:20 | 显示全部楼层
本帖最后由 CListery 于 2024-7-10 15:42 编辑

第十九和二十课:
1. 通过 bdata 关键字修饰的变量可以通过 sbit 再对该变量的位起别名,这样就可以更加方便的进行单独某一位的修改
2. 数码管和 LED 的 IO 口相同时,为了避免刷新 LED 或数码管时互相影响,可以通过在定时器中断的不同的瞬间开关控制脚的高低电平实现 IO 口的复用
3. 为了程序的可移植性,不要直接使用 IO 口,而是通过重新定义的方式给 IO 口重新命名,如果更换其他引脚不同的芯片时,只需要修改定义的地方就可以了

复习心得:
1. 可以通过 #define 来直接访问数组的某一位,类似 sbit 功能

u8 SEG_DATA[2] = {0xFF, 0xFF};

#define SEG0 SEG_DATA[0]
#define SEG1 SEG_DATA[1]


2. 使用 #define 时需要注意
#define LED_EN P40 // 这里不能使用 P4^0


3. 代码

led.h
  1. #ifndef __LED_H
  2. #define __LED_H
  3. #include "stc32g.h"
  4. #include "stc32_stc8_usb.h"
  5. // 数码管使能
  6. #define SEG_ENABLE P7
  7. // 数码管显示控制
  8. #define SEG_SHOW_CONTROL P6
  9. // 发光二极管使能
  10. #define LED_ENABLE P40
  11. // 发光二极管显示控制
  12. #define LED_SHOW_CONTROL P6
  13. // 数码管显示位总控制变量
  14. extern u8 SEG_POS_ENABLE[8];
  15. // 数码管分位控制变量
  16. #define SPE0 SEG_POS_ENABLE[0]
  17. #define SPE1 SEG_POS_ENABLE[1]
  18. #define SPE2 SEG_POS_ENABLE[2]
  19. #define SPE3 SEG_POS_ENABLE[3]
  20. #define SPE4 SEG_POS_ENABLE[4]
  21. #define SPE5 SEG_POS_ENABLE[5]
  22. #define SPE6 SEG_POS_ENABLE[6]
  23. #define SPE7 SEG_POS_ENABLE[7]
  24. // 数码管显示的数据总控制变量,对应 SEG_NUM_MAP 的值
  25. extern u8 SEG_SHOW_DATA[8];
  26. // 数码管每位显示的数据变量,对应 SEG_NUM_MAP 的值
  27. #define SSD0 SEG_SHOW_DATA[0]
  28. #define SSD1 SEG_SHOW_DATA[1]
  29. #define SSD2 SEG_SHOW_DATA[2]
  30. #define SSD3 SEG_SHOW_DATA[3]
  31. #define SSD4 SEG_SHOW_DATA[4]
  32. #define SSD5 SEG_SHOW_DATA[5]
  33. #define SSD6 SEG_SHOW_DATA[6]
  34. #define SSD7 SEG_SHOW_DATA[7]
  35. // 发光二极管使能总控制变量
  36. extern u8 bdata LED_SHOW_DATA;
  37. // 发光二极管使能每位控制变量
  38. extern bit LSD0;
  39. extern bit LSD1;
  40. extern bit LSD2;
  41. extern bit LSD3;
  42. extern bit LSD4;
  43. extern bit LSD5;
  44. extern bit LSD6;
  45. extern bit LSD7;
  46. void refreshLight();
  47. #endif
复制代码
led.c
  1. #include "led.h"
  2. // 数码管显示数据
  3. u8 SEG_NUM_MAP[11] = {
  4.     0xC0, // 0
  5.     0xF9, // 1
  6.     0xA4, // 2
  7.     0xB0, // 3
  8.     0x99, // 4
  9.     0x92, // 5
  10.     0x82, // 6
  11.     0xF8, // 7
  12.     0x80, // 8
  13.     0x90, // 9
  14.     0xFF  // 不显示
  15. };
  16. u8 SEG_POS_DATA[8] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
  17. u8 SEG_POS_ENABLE[8] = {1, 1, 1, 1, 1, 1, 1, 1};
  18. u8 SEG_SHOW_DATA[8] = {11, 11, 11, 11, 11, 11, 11, 11};
  19. u8 bdata LED_SHOW_DATA = 0xFF;
  20. sbit LSD0 = LED_SHOW_DATA^0;
  21. sbit LSD1 = LED_SHOW_DATA^1;
  22. sbit LSD2 = LED_SHOW_DATA^2;
  23. sbit LSD3 = LED_SHOW_DATA^3;
  24. sbit LSD4 = LED_SHOW_DATA^4;
  25. sbit LSD5 = LED_SHOW_DATA^5;
  26. sbit LSD6 = LED_SHOW_DATA^6;
  27. sbit LSD7 = LED_SHOW_DATA^7;
  28. void refreshLight()
  29. {
  30.   static u8 num = 0;
  31.   if (num <= 7)
  32.   {
  33.     LED_ENABLE = 1;
  34.     if (SEG_SHOW_DATA[num] == 11 || SEG_POS_ENABLE[num])
  35.     {
  36.       SEG_ENABLE = 0xFF;
  37.     }
  38.     else
  39.     {
  40.       SEG_ENABLE = SEG_POS_DATA[num];
  41.       SEG_SHOW_CONTROL = SEG_NUM_MAP[SEG_SHOW_DATA[num]];
  42.     }
  43.   }
  44.   else if (num <= 14)
  45.   {
  46.     SEG_ENABLE = 0xFF;
  47.     LED_ENABLE = 0;
  48.     LED_SHOW_CONTROL = LED_SHOW_DATA;
  49.   }
  50.   else
  51.   {
  52.     SEG_ENABLE = 0xFF;
  53.     LED_ENABLE = 1;
  54.   }
  55.   num++;
  56.   if (num > 15)
  57.   {
  58.     num = 0;
  59.   }
  60. }
复制代码
key.h
  1. #ifndef __KEY_H_
  2. #define __KEY_H_
  3. #include "STC32G.H"
  4. #include "STC32_STC8_USB.H"
  5. extern u16 KEY_STATES[8];
  6. #define KEY1 2 // P32
  7. #define KEY2 3 // P33
  8. #define KEY3 4 // P34
  9. #define KEY4 5 // P35
  10. #define KEY_NORMAL 1       // 未点击
  11. #define KEY_CLICK 2        // 单击
  12. #define KEY_DOUBAL_CLICK 3 // 双击
  13. #define KEY_LONG_CLICK 4   // 长按
  14. #define KEY_SHAKE_TIMEOUT 30
  15. #define KEY_DOUBLE_CLICK_TIMEOUT 500                                                  // 双击超时时间
  16. #define KEY_DOUBLE_CLICK_MASK 10000                                                   // 双击检测掩码位
  17. #define KEY_DOUBLE_CLICK_THRESHOLD (KEY_DOUBLE_CLICK_TIMEOUT + KEY_DOUBLE_CLICK_MASK) // 双击检测阈值
  18. #define KEY_LONG_CLICK_TIMEOUT 3000
  19. void refreshKeyStatus();
  20. u8 readKeyStatus(u8 keyId);
  21. #endif
复制代码
key.c
  1. #include "key.h"
  2. #define KEY_GPIO P3
  3. u16 KEY_STATES[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  4. /**
  5. * 按键状态刷新
  6. * 每10ms执行一次
  7. */
  8. void refreshKeyStatus()
  9. {
  10.   u8 pos = 0;
  11.   for (pos = 0; pos < 8; pos++)
  12.   {
  13.     if (~KEY_GPIO & (1 << pos))
  14.     {
  15.       // 判断按键是否已经进入双击检测
  16.       if (KEY_STATES[pos] > KEY_DOUBLE_CLICK_MASK)
  17.       {
  18.         // 标记为双击状态
  19.         KEY_STATES[pos] = KEY_DOUBLE_CLICK_THRESHOLD + 1;
  20.       }
  21.       else
  22.       {
  23.         KEY_STATES[pos] += 10;
  24.         if (KEY_STATES[pos] > KEY_LONG_CLICK_TIMEOUT)
  25.         {
  26.           // 标记为双击状态
  27.           KEY_STATES[pos] = KEY_LONG_CLICK_TIMEOUT + 1;
  28.         }
  29.       }
  30.     }
  31.     else
  32.     {
  33.       // 30 < s < 3000 进入双击检测
  34.       if (KEY_STATES[pos] > KEY_SHAKE_TIMEOUT && KEY_STATES[pos] < KEY_LONG_CLICK_TIMEOUT)
  35.       {
  36.         // 按键按下过,并且按键没有触发过长按事件
  37.         // 进入双击超时检测
  38.         // 11000
  39.         KEY_STATES[pos] = KEY_DOUBLE_CLICK_THRESHOLD;
  40.         KEY_STATES[pos] -= 10;
  41.       }
  42.       else if (KEY_STATES[pos] > KEY_DOUBLE_CLICK_MASK && KEY_STATES[pos] < KEY_DOUBLE_CLICK_THRESHOLD)
  43.       {
  44.         // 双击超时计数
  45.         KEY_STATES[pos] -= 10;
  46.         if (KEY_STATES[pos] <= KEY_DOUBLE_CLICK_MASK)
  47.         {
  48.           // 双击超时,重置计数
  49.           KEY_STATES[pos] = 0;
  50.         }
  51.       }
  52.       else
  53.       {
  54.         KEY_STATES[pos] = 0;
  55.       }
  56.     }
  57.   }
  58. }
  59. u8 readKeyStatus(u8 keyId)
  60. {
  61.   if (KEY_STATES[keyId] > KEY_DOUBLE_CLICK_THRESHOLD)
  62.   {
  63.     return KEY_DOUBAL_CLICK;
  64.   }
  65.   else if (KEY_STATES[keyId] > KEY_LONG_CLICK_TIMEOUT && KEY_STATES[keyId] < KEY_DOUBLE_CLICK_MASK)
  66.   {
  67.     return KEY_LONG_CLICK;
  68.   }
  69.   else if (KEY_STATES[keyId] > KEY_SHAKE_TIMEOUT && KEY_STATES[keyId] < KEY_DOUBLE_CLICK_MASK)
  70.   {
  71.     return KEY_CLICK;
  72.   }
  73.   return KEY_NORMAL;
  74. }
复制代码
main.c
  1. #include <STC32G.H>
  2. #include <STC32_STC8_USB.H>
  3. #include "delay_24mhz.h"
  4. #include "led.h"
  5. #include "key.h"
  6. char *USER_DEVICEDESC = NULL;
  7. char *USER_PRODUCTDESC = NULL;
  8. char *USER_STCISPCMD = "@STCISP#";
  9. void sys_init()
  10. {
  11.   WTST = 0;
  12.   EAXFR = 1;
  13.   CKCON = 0;
  14. }
  15. void set_interrupt()
  16. {
  17.   AUXR &= 0xBF; // 清理 T1 速度控制位
  18.   AUXR |= 0x40; // 设置 T1 为 1T 模式,即不分频
  19.   TMOD &= 0x0F; // 清理 T1 模式寄存器
  20.   TMOD |= 0x40; // 设置 T1 为16位自动重载计数器模式且无需上拉 INT1 引脚
  21.   // 设置外部 P3.5 拉低一次触发一次 T1 计数器中断
  22.   TL1 = 0xFF; // 计数器T1设置低八位起始值
  23.   TH1 = 0xFF; // 计数器T1设置高八位起始值
  24.   TF1 = 0; // T1 溢出标志
  25.   TR1 = 1; // T1 运行控制位
  26.   ET1 = 1; // T1 开关
  27.   AUXR &= 0x7F; // 清理 T0 速度控制位
  28.   AUXR |= 0x00; // 设置 T0 为 12T 模式
  29.   TMOD &= 0xF0; // 清理 T0 模式寄存器
  30.   TMOD |= 0x00; // 设置 T0 为16位自动重载定时器模式且无需上拉 INT0 引脚
  31.   // 设置 1 毫秒触发一次 T0 计时器中断
  32.   TL0 = 0x30; // 计数器T1设置低八位起始值
  33.   TH0 = 0xF8; // 计数器T1设置高八位起始值
  34.   TF0 = 0; // T0 溢出标志
  35.   TR0 = 1; // T0 运行控制位
  36.   ET0 = 1; // T0 开关
  37.   EA = 1; // 中断总开关
  38. }
  39. void main()
  40. {
  41.   sys_init();
  42.   usb_init();
  43.   set_interrupt();
  44.   P4M0 = 0;
  45.   P4M1 = 0;
  46.   P6M0 = 0;
  47.   P6M1 = 0;
  48.   P7M0 = 0;
  49.   P7M1 = 0;
  50.   // P3PU = 1;
  51.   // SPE0 = 0;
  52.   // SPE1 = 1;
  53.   // SPE2 = 0;
  54.   // SPE3 = 1;
  55.   // SPE4 = 0;
  56.   // SPE5 = 1;
  57.   // SPE6 = 0;
  58.   // SPE7 = 1;
  59.   // SSD0 = 8;
  60.   // SSD1 = 7;
  61.   // SSD2 = 6;
  62.   // SSD3 = 5;
  63.   // SSD4 = 4;
  64.   // SSD5 = 3;
  65.   // SSD6 = 2;
  66.   // SSD7 = 1;
  67.   // LSD0 = 0;
  68.   while (1)
  69.   {
  70.     u8 num = 0;
  71.     // delay_1s();
  72.     // for (num = 0; num < 8; num++)
  73.     // {
  74.     //   SEG_POS_ENABLE[num] = !SEG_POS_ENABLE[num];
  75.     // }
  76.     // LED_SHOW_DATA = ~((~LED_SHOW_DATA) << 1);
  77.     // if (LED_SHOW_DATA == 0xFF)
  78.     // {
  79.     //   LSD0 = 0;
  80.     // }
  81.     if (readKeyStatus(KEY1) == KEY_DOUBAL_CLICK)
  82.     {
  83.       LSD7 = 0;
  84.       delay_ms(100);
  85.       LSD7 = 1;
  86.       delay_ms(100);
  87.       LSD7 = 0;
  88.       delay_ms(100);
  89.     }
  90.     else if (readKeyStatus(KEY1) == KEY_LONG_CLICK)
  91.     {
  92.       LED_SHOW_DATA = 0xFE;
  93.       for (num = 0; num < 8; num++)
  94.       {
  95.         LED_SHOW_DATA = (LED_SHOW_DATA << 1);
  96.         delay_ms(100);
  97.       }
  98.     }
  99.     else if (readKeyStatus(KEY1) == KEY_CLICK)
  100.     {
  101.       LSD2 = 0;
  102.     }
  103.     else
  104.     {
  105.       LED_SHOW_DATA = 0xFF;
  106.     }
  107.   }
  108. }
  109. void T0_run(void) interrupt 1
  110. {
  111.   static u8 count = 0;
  112.   if (count >= 9)
  113.   {
  114.     refreshKeyStatus();
  115.     count = 0;
  116.   }
  117.   count++;
  118.   refreshLight();
  119. }
  120. void T1_run(void) interrupt 3
  121. {
  122.   // LSD0 = !LSD0;
  123. }
复制代码








回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-7-4 10:51:09 | 显示全部楼层
本帖最后由 CListery 于 2024-7-11 15:54 编辑

第二十一课:
通过自增变量记录状态切换(状态机),这样就可以省略掉主函数中的延时操作,从而达到多任务的处理效果

复习:
通过计数实现延时功能
  1. #include <STC32G.H>
  2. #include <STC32_STC8_USB.H>
  3. #include "delay_24mhz.h"
  4. #include "led.h"
  5. #include "key.h"
  6. char *USER_DEVICEDESC = NULL;
  7. char *USER_PRODUCTDESC = NULL;
  8. char *USER_STCISPCMD = "@STCISP#";
  9. bit T_100MS_FLAG;
  10. void sys_init()
  11. {
  12.   WTST = 0;
  13.   EAXFR = 1;
  14.   CKCON = 0;
  15. }
  16. void set_interrupt()
  17. {
  18.   AUXR &= 0xBF; // 清理 T1 速度控制位
  19.   AUXR |= 0x40; // 设置 T1 为 1T 模式,即不分频
  20.   TMOD &= 0x0F; // 清理 T1 模式寄存器
  21.   TMOD |= 0x40; // 设置 T1 为16位自动重载计数器模式且无需上拉 INT1 引脚
  22.   // 设置外部 P3.5 拉低一次触发一次 T1 计数器中断
  23.   TL1 = 0xFF; // 计数器T1设置低八位起始值
  24.   TH1 = 0xFF; // 计数器T1设置高八位起始值
  25.   TF1 = 0; // T1 溢出标志
  26.   TR1 = 1; // T1 运行控制位
  27.   ET1 = 1; // T1 开关
  28.   AUXR &= 0x7F; // 清理 T0 速度控制位
  29.   AUXR |= 0x00; // 设置 T0 为 12T 模式
  30.   TMOD &= 0xF0; // 清理 T0 模式寄存器
  31.   TMOD |= 0x00; // 设置 T0 为16位自动重载定时器模式且无需上拉 INT0 引脚
  32.   // 设置 1 毫秒触发一次 T0 计时器中断
  33.   TL0 = 0x30; // 计数器 T0 设置低八位起始值
  34.   TH0 = 0xF8; // 计数器 T0 设置高八位起始值
  35.   TF0 = 0; // T0 溢出标志
  36.   TR0 = 1; // T0 运行控制位
  37.   ET0 = 1; // T0 开关
  38.   EA = 1; // 中断总开关
  39. }
  40. void main()
  41. {
  42.   sys_init();
  43.   usb_init();
  44.   set_interrupt();
  45.   P4M0 = 0;
  46.   P4M1 = 0;
  47.   P6M0 = 0;
  48.   P6M1 = 0;
  49.   P7M0 = 0;
  50.   P7M1 = 0;
  51.   // P3PU = 1;
  52.   // SPE0 = 0;
  53.   // SPE1 = 1;
  54.   // SPE2 = 0;
  55.   // SPE3 = 1;
  56.   // SPE4 = 0;
  57.   // SPE5 = 1;
  58.   // SPE6 = 0;
  59.   // SPE7 = 1;
  60.   // SSD0 = 8;
  61.   // SSD1 = 7;
  62.   // SSD2 = 6;
  63.   // SSD3 = 5;
  64.   // SSD4 = 4;
  65.   // SSD5 = 3;
  66.   // SSD6 = 2;
  67.   // SSD7 = 1;
  68.   // LSD0 = 0;
  69.   LED_SHOW_DATA = 0xFF;
  70.   while (1)
  71.   {
  72.     u8 num = 0;
  73.     u16 s = 0;
  74.     // delay_1s();
  75.     // for (num = 0; num < 8; num++)
  76.     // {
  77.     //   SEG_POS_ENABLE[num] = !SEG_POS_ENABLE[num];
  78.     // }
  79.     // LED_SHOW_DATA = ~((~LED_SHOW_DATA) << 1);
  80.     // if (LED_SHOW_DATA == 0xFF)
  81.     // {
  82.     //   LSD0 = 0;
  83.     // }
  84.     if (readKeyStatus(KEY1) == KEY_DOUBAL_CLICK)
  85.     {
  86.       while (readKeyStatus(KEY1) == KEY_DOUBAL_CLICK)
  87.         ;
  88.       s = 0;
  89.       do
  90.       {
  91.         if (T_100MS_FLAG)
  92.         {
  93.           LSD7 = !LSD7;
  94.           T_100MS_FLAG = 0;
  95.           while (T_100MS_FLAG)
  96.             ;
  97.           s++;
  98.         }
  99.       } while (s < 6);
  100.     }
  101.     else if (readKeyStatus(KEY1) == KEY_LONG_CLICK)
  102.     {
  103.       LED_SHOW_DATA = 0xFE;
  104.       delay_ms(100);
  105.       for (num = 0; num < 7; num++)
  106.       {
  107.         LED_SHOW_DATA = (LED_SHOW_DATA << 1);
  108.         delay_ms(100);
  109.       }
  110.     }
  111.     else if (readKeyStatus(KEY1) == KEY_CLICK)
  112.     {
  113.       LSD2 = 0;
  114.     }
  115.     else
  116.     {
  117.       LED_SHOW_DATA = 0xFF;
  118.     }
  119.   }
  120. }
  121. void T0_run(void) interrupt 1
  122. {
  123.   static u8 count = 0;
  124.   count++;
  125.   if (count % 200 == 0)
  126.   {
  127.     T_100MS_FLAG = 1;
  128.   }
  129.   if (count % 10 == 0)
  130.   {
  131.     refreshKeyStatus();
  132.   }
  133.   if (count >= 200)
  134.   {
  135.     count = 0;
  136.   }
  137.   refreshLight();
  138. }
  139. void T1_run(void) interrupt 3
  140. {
  141.   // LSD0 = !LSD0;
  142. }
复制代码


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-7-22 17:23:38 | 显示全部楼层
本帖最后由 CListery 于 2024-7-22 17:24 编辑

第二十二课:
1.学习矩阵键盘的使用
2.学习通过异或位运算实现行列数据扫描
3.学习 switch case 和 #define 的结合使用
  1. /**
  2. * 读取矩阵按键
  3. */
  4. u8 readMatrxKeyStatus(void)
  5. {
  6.   u8 status = 0;
  7.   // 行扫描
  8.   MATRX_KEY = 0xC0; // 1100 0000  P07,P06 拉高
  9.   wait();
  10.   status = MATRX_KEY ^ 0xC0; // 使用位运算的异或算出哪个行被拉低,假设 P06 被拉低,1000 0000 ^ 1100 0000 = 0100 0000
  11.   // 列扫描
  12.   MATRX_KEY = 0x0F; // 0000 1111  P00-P03 拉高
  13.   wait();
  14.   status |= MATRX_KEY ^ 0x0F; // 使用位运算的异或算出哪个列被拉低,假设 P03 被拉低,0000 0111 ^ 0000 1111 = 0000 1000
  15.   // 1100 1111
  16.   // 0000 0000
  17.   // if (status != 0)
  18.   // {
  19.   //   printf("0x%02X\r\n", status);
  20.   // }
  21.   return status;
  22. }
复制代码

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-7-23 11:07:15 | 显示全部楼层
第二十三课:
1. 学习外部中断
  1. void initExtInt0()
  2. {
  3.   IT0 = 1; // 下降沿触发
  4.   EX0 = 1; // 外部中断 0 使能
  5.   IE0 = 0; // 重置中断标志位
  6. }
  7. void initExtInt1()
  8. {
  9.   IT1 = 1; // 下降沿触发
  10.   EX1 = 1; // 外部中断 1 使能
  11.   IE1 = 0; // 重置中断标志位
  12. }
  13. void initExtInt2()
  14. {
  15.   EX2 = 1;    // 使能位
  16.   INT2IF = 0; // 重置中断标志位
  17. }
  18. void initExtInt3()
  19. {
  20.   EX3 = 1;    // 使能位
  21.   INT3IF = 0; // 重置中断标志位
  22. }
  23. void initExtInt4()
  24. {
  25.   EX4 = 1;    // 使能位
  26.   INT4IF = 0; // 重置中断标志位
  27. }
复制代码
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-7-23 11:27:09 | 显示全部楼层
本帖最后由 CListery 于 2024-7-29 10:54 编辑

第二十四课:
1.学习 GPIO 中断
2.学习中断向量超过31时如何处理
3.学习设置中断优先级
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-7-24 10:40:21 | 显示全部楼层
用 8051U + SHT40-BD1F 整了个温湿度检测仪



项目链接 https://oshwhub.com/clistery/tem ... y-detector-6246631a
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-7-29 16:31:10 | 显示全部楼层
第二十五和二十六课:
1. 学习 ADC 模数转换及其寄存器的操作
2. 学习查询方式和中断方式获取 ADC 数值(中断方式只是比查询方式多操作一个 EADC 中断标志位)
  1. void initADC(bit enInterrupt)
  2. {
  3.   P1M0 = 0x00;
  4.   P1M1 = 0x01;
  5.   ADCCFG = 0x2F;
  6.   ADCTIM = 0x2F;
  7.   ADC_CONTR = 0x80;
  8.   EADC = enInterrupt;
  9. }
  10. u16 queryADC(u8 channel)
  11. {
  12.   ADC_RES = 0;
  13.   ADC_RESL = 0;
  14.   ADC_CONTR |= channel;
  15.   ADC_START = 1;
  16.   ADC_FLAG = 0;
  17.   _nop_();
  18.   _nop_();
  19.   while (!ADC_FLAG)
  20.     ;
  21.   return (ADC_RES << 8) | ADC_RESL;
  22. }
  23. u16 convertVoltage(u16 adcRatio)
  24. {
  25.   return 2.5 / 4096 * adcRatio * 1000;
  26. }
复制代码
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-8-2 08:39:02 | 显示全部楼层
fzt*** 发表于 2024-8-2 01:09
感谢,学习了~~~~~~~~~

共勉
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民II
  • 打卡总天数:98
  • 最近打卡:2025-02-18 09:33:29

1

主题

32

回帖

486

积分

中级会员

积分
486
发表于 2024-8-2 10:09:35 | 显示全部楼层
本帖最后由 CListery 于 2024-8-2 11:42 编辑

第二十七集:
1.通过内部基准电压反推Vref电压
  1. #define VREFH_ADDR CHIPID7
  2. #define VREFL_ADDR CHIPID8
  3. u16 vrefVoltage()
  4. {
  5.   u16 innerVref, outVref = 0;
  6.   u8 i;
  7.   innerVref = (VREFH_ADDR << 8) | VREFL_ADDR;
  8.   queryADC(15);
  9.   queryADC(15);
  10.   for (i = 0; i < 8; i++)
  11.   {
  12.     outVref += queryADC(15);
  13.   }
  14.   outVref /= 8;
  15.   return 4096L * innerVref / outVref;
  16. }
复制代码
2.读取按键按下
  1. #define ADC_UNIT 256
  2. #define ADC_OFFSET (ADC_UNIT / 4)
  3. #define ADC_MIN_RATIO (ADC_UNIT - ADC_OFFSET)
  4. #define ADC_MAX_RATIO (ADC_UNIT * 16 + ADC_OFFSET)
  5. char adcKeyRead(u8 channel)
  6. {
  7.   u16 adcRatio;
  8.   char keyIndex = -1;
  9.   adcRatio = queryADC(channel);
  10.   if (adcRatio < ADC_MIN_RATIO || adcRatio > ADC_MAX_RATIO)
  11.   {
  12.     return keyIndex;
  13.   }
  14.   for (keyIndex = 1; keyIndex <= 16; keyIndex++)
  15.   {
  16.     if(adcRatio > ADC_UNIT * keyIndex - ADC_OFFSET && adcRatio < ADC_UNIT * keyIndex + ADC_OFFSET)
  17.     {
  18.       return keyIndex;
  19.     }
  20.   }
  21.   return keyIndex;
  22. }
复制代码
3.每100ms调用一次按键读取,按键按下3秒触发长按
  1. #define ADC_UNIT 256
  2. #define ADC_OFFSET (ADC_UNIT / 4)
  3. #define ADC_MIN_RATIO (ADC_UNIT - ADC_OFFSET)
  4. #define ADC_MAX_RATIO (ADC_UNIT * 16 + ADC_OFFSET)
  5. char adcKeyRead(u8 channel)
  6. {
  7.   u16 adcRatio;
  8.   u8 i;
  9.   char keyIndex = -1;
  10.   static u8 times = 0;
  11.   adcRatio = queryADC(channel);
  12.   if (adcRatio < ADC_MIN_RATIO || adcRatio > ADC_MAX_RATIO)
  13.   {
  14.     times = 0;
  15.     return keyIndex;
  16.   }
  17.   for (i = 1; i <= 16; i++)
  18.   {
  19.     if (adcRatio > ADC_UNIT * i - ADC_OFFSET && adcRatio < ADC_UNIT * i + ADC_OFFSET)
  20.     {
  21.       keyIndex = i;
  22.       times++;
  23.       if (times > 30)
  24.       {
  25.         times = 30;
  26.         keyIndex = ~keyIndex;
  27.       }
  28.       return keyIndex;
  29.     }
  30.   }
  31.   return keyIndex;
  32. }
复制代码






回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-9 03:05 , Processed in 0.162152 second(s), 103 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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