找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1232|回复: 20
收起左侧

九齐NY8A051H单片机程序,大佬帮忙看看,灯效进行不下去

[复制链接]
ID:1077269 发表于 2025-8-2 11:11 | 显示全部楼层 |阅读模式
这是我写的一个按键切换3颗LED灯的灯光效果代码,想要实现的效果是,按下开关,实现灯效:
(1)3颗LED灯全亮;
(2)3颗LED灯全亮2秒,全灭2秒,循环;
(3)只有1号灯亮2秒,接着,只有2号灯亮2秒,最后只有3号灯亮2秒,循环;
(4)3颗LED灯全灭,进入睡眠;
全局效果:当有LED灯点亮时,开始倒计时30分钟,期间没有按下开关,LED灯全灭,IC进入睡眠,等待开关唤醒。

目前我的代码只能在两个灯效之间切换,无法做的4个灯效切换,而且延时30分钟效果不知道怎么进行,求大佬帮忙完善一下!!!

按键切换3灯灯效.docx

12.75 KB, 下载次数: 0

代码

回复

使用道具 举报

无效楼层,该帖已经被删除
ID:1089588 发表于 2025-8-4 14:14 | 显示全部楼层
有开总中断吗,你的delay要2000
回复

使用道具 举报

ID:1157445 发表于 2025-8-4 15:51 | 显示全部楼层
按键部分的问题:1、按下以后Mod会一直加,最好是识别到弹起再加一;2、Mod等于4就置零需要写在Mod++后面,且最好是大于等于4;3、switch增加default。
回复

使用道具 举报

ID:1073939 发表于 2025-8-8 13:33 | 显示全部楼层
代码结构有问题。你这种软件延时在代码更改工作模式后还是会继续延时,不会立即按新模式进行。要以状态机的方式组织代码。
回复

使用道具 举报

ID:1077269 发表于 2025-8-12 12:00 | 显示全部楼层
a825563619 发表于 2025-8-4 14:14
有开总中断吗,你的delay要2000

delay时间长了,watchdog 重置了,灯一直频闪,现在不知道怎么操作,刚接触这款单片机,大佬能不能帮我改一下?
回复

使用道具 举报

ID:1077269 发表于 2025-8-12 12:03 | 显示全部楼层
柠檬脆片 发表于 2025-8-4 15:51
按键部分的问题:1、按下以后Mod会一直加,最好是识别到弹起再加一;2、Mod等于4就置零需要写在Mod++后面, ...

按键部分我是沿用官方示例代码的,应该不会出错,我现在尝试一下default语句
回复

使用道具 举报

ID:1077269 发表于 2025-8-12 12:05 | 显示全部楼层
ydatou 发表于 2025-8-8 13:33
代码结构有问题。你这种软件延时在代码更改工作模式后还是会继续延时,不会立即按新模式进行。要以状态机的 ...

不太明白是什么意思,我刚接触单片机,网上都说九齐的容易学,大佬能不能帮我改一下?
回复

使用道具 举报

ID:1073939 发表于 2025-8-16 14:56 | 显示全部楼层
setsu 发表于 2025-8-12 12:05
不太明白是什么意思,我刚接触单片机,网上都说九齐的容易学,大佬能不能帮我改一下?

暂时用你的软延时改了下。代码中不要有长时间(大于10毫秒)延时,中断中延时不要超过10us。
回复

使用道具 举报

ID:1077269 发表于 2025-8-16 15:30 | 显示全部楼层
ydatou 发表于 2025-8-16 14:56
暂时用你的软延时改了下。代码中不要有长时间(大于10毫秒)延时,中断中延时不要超过10us。

能发出来看看吗?
回复

使用道具 举报

ID:1073939 发表于 2025-8-16 15:58 | 显示全部楼层
setsu 发表于 2025-8-12 12:05
不太明白是什么意思,我刚接触单片机,网上都说九齐的容易学,大佬能不能帮我改一下?

用你的软延时做了个状态机。
以后编程要注意几点:
1.中断中延时不要超过10uS,不要做复杂运算。
2.不要使用超过20mS的延时,如有超过,请用状态机实现。
3.多使用标志。
4.其中10ms延时要用定时器实现。
  1. #include <ny8.h>
  2. #include "ny8_constant.h"
  3. #include "stdint.h"
  4. #define UPDATE_REG(x) __asm__("MOVR _" #x ",F")
  5. #define unchar unsigned char
  6. #define unint unsigned int

  7. unchar myvar; // 九齐单片机位定义,将一个char拆成8个bit变量
  8. __sbit key = PORTB : 0;
  9. __sbit light1 = PORTB : 1;
  10. __sbit light2 = PORTB : 2;
  11. __sbit light3 = PORTB : 4;
  12. #define light_get() (((PORTB >> 1) & 7) ? 1 : 0)
  13. #define light_set(x)             \
  14.         do                           \
  15.         {                            \
  16.                 PORTB &= 0xf1;           \
  17.                 PORTB |= ((x) & 7) << 1; \
  18.         } while (0)(PORTB |= 0x1 << x)

  19. unint Mod = 3;
  20. unint ModCnt = 0; // 计时,每10mS加1

  21. unchar keyFlag = 0;
  22. unchar keyCnt = 0; // 计时,每10mS加1

  23. unint sleepCnt = 0; // 计时,每10mS加1

  24. void delay(unint z) // 延时函数ms
  25. {
  26.         unint x, y;
  27.         for (x = z; x > 0; x--)
  28.                 for (y = 100; y > 0; y--)
  29.                         ;
  30. }
  31. void keyProc(void) // 按键处理函数,每10mS调用一次
  32. {
  33.         unchar i = key ? 1 : 0;
  34.         if (++keyCnt == 0)
  35.                 keyCnt--;
  36.         if (i == 0) // 按键按下
  37.         {
  38.                 if (keyFlag)
  39.                         keyCnt = 0;         // 按键按下计时开始
  40.                 if (keyCnt == 2) // 消抖
  41.                 {
  42.                         ModCnt = 0;
  43.                         if (++Mod == 4)
  44.                                 Mod = 0;
  45.                 }
  46.                 sleepCnt = 0;
  47.         }
  48.         else
  49.         {
  50.                 if (keyFlag == 0)
  51.                 {
  52.                         // 松手检测,如有松手要处理的代码写在这里
  53.                         sleepCnt = 0;
  54.                 }
  55.         }
  56.         keyFlag = i;
  57. }
  58. void ModProc(void)
  59. {
  60.         switch (Mod)
  61.         {
  62.         case 3: // 灯全灭
  63.                 if (ModCnt == 0)
  64.                         light_set(0);
  65.                 SLEEP(); // LED灯全灭,IC进入睡眠
  66.                 break;
  67.         case 0: // 灯全亮
  68.                 if (ModCnt == 0)
  69.                         light_set(7);
  70.                 break;
  71.         case 1: // 灯1亮 2秒,接着灯2亮 2秒,灯3亮 2秒
  72.                 if (ModCnt == 0 || ModCnt >= 600)
  73.                 {
  74.                         ModCnt = 0;
  75.                         light_set(1);
  76.                 }
  77.                 else if (ModCnt == 200)
  78.                         light_set(2);
  79.                 else if (ModCnt == 400)
  80.                         light_set(4);
  81.                 break;
  82.         case 2: // 灯全亮2秒,全灭两秒
  83.                 if (ModCnt == 0 || ModCnt >= 400)
  84.                         light_set(7);
  85.                 else if (ModCnt == 200)
  86.                         light_set(0);
  87.                 break;
  88.         default:
  89.                 Mod = 3;
  90.                 ModCnt = -1;
  91.                 break;
  92.         }

  93.         if (++sleepCnt >= 30 * 60 * 100) // 30分钟
  94.         {
  95.                 light_set(0);
  96.                 SLEEP(); // 点亮30分钟期间没有按下开关(按下会使sleepCnt清零),IC进入睡眠
  97.         }
  98. }

  99. void isr(void) __interrupt(0)
  100. {
  101.         // if(INTFbits.INTIF)
  102.         //{
  103.         //        //INTF = (unsigned char)~(C_INT_EXT);
  104.         //}

  105.         if (INTFbits.PBIF)
  106.         {
  107.                 INTFbits.PBIF = 0;
  108.                 sleepCnt = 0;
  109.         }
  110. }

  111. void lnit_Timer() // 中断初始化
  112. {
  113.         DISI();                                // 禁用中断
  114.         INTE = C_INT_PBKey; // 启用PB按键中断
  115.         ENI();                                // 启用中断
  116. }

  117. void lnit_Mod()
  118. {
  119.         BPHCON = (unsigned char)~(C_PB0_PHB); // 开启B0口上来电阻
  120.         BWUCON = C_PB0_Wakeup;                                  // 启用PB0输入唤醒功能
  121.         IOSTB = C_PB0_Input;
  122.         PORTB = 0x00;
  123. }

  124. void main(void)
  125. {
  126.         lnit_Mod();
  127.         lnit_Timer();
  128.         Mod = 0;
  129.         key = 1;
  130.         while (1)
  131.         {
  132.                 CLRWDT();
  133.                 delay(1); // 10mS,最好用定时器代替延时函数。
  134.                 keyProc();
  135.                 ModProc();
  136.         }
  137.         // while (1)
  138.         // {
  139.         //         if (gb10ms_flag) // 定时器中断使 gb10ms_flag=1
  140.         //         {
  141.         //                 gb10ms_flag = 0;
  142.         //                 CLRWDT();
  143.         //                 keyProc();
  144.         //                 ModProc()
  145.         //         }
  146.         // }
  147. }
复制代码



评分

参与人数 1黑币 +100 收起 理由
admin + 100 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:1073939 发表于 2025-8-16 16:32 | 显示全部楼层
代码中有处错误:sleepCnt最大值为65535,而30分钟为180000次10ms。
还要加一个变量。

  1.         if (++ModCntL >= 100)//秒
  2.         {
  3.                 ModCntL = 0;
  4.                 if (++sleepCnt >= 30 * 60) // 30分钟
  5.                 {
  6.                         light_set(0);
  7.                         SLEEP(); // 点亮30分钟期间没有按下开关(按下会使sleepCnt清零),IC进入睡眠
  8.                 }
  9.         }
复制代码
回复

使用道具 举报

ID:1077269 发表于 2025-8-18 11:12 | 显示全部楼层
ydatou 发表于 2025-8-16 15:58
用你的软延时做了个状态机。
以后编程要注意几点:
1.中断中延时不要超过10uS,不要做复杂运算。

#define light_set(x)             \
        do                           \
        {                            \
                PORTB &= 0xf1;           \
                PORTB |= ((x) & 7) << 1; \
        } while (0)(PORTB |= 0x1 << x)
大佬,这个位置编译报错,是不是九齐用不了do while语句啊?
回复

使用道具 举报

ID:1077269 发表于 2025-8-18 11:19 | 显示全部楼层
ydatou 发表于 2025-8-16 15:58
用你的软延时做了个状态机。
以后编程要注意几点:
1.中断中延时不要超过10uS,不要做复杂运算。

  case 1: // 灯1亮 2秒,接着灯2亮 2秒,灯3亮 2秒
                if (ModCnt == 0 || ModCnt >= 600)
                {
                        ModCnt = 0;
                        light_set(1);
                }
                else if (ModCnt == 200)
                        light_set(2);
                else if (ModCnt == 400)
                        light_set(4);
                break;
现在报错提示是第二个else之前出现语法错误,不知道哪里出错了。。。
回复

使用道具 举报

ID:1077269 发表于 2025-8-18 16:24 | 显示全部楼层
ydatou 发表于 2025-8-16 15:58
用你的软延时做了个状态机。
以后编程要注意几点:
1.中断中延时不要超过10uS,不要做复杂运算。

目前我把一些编译报错都给改了,现在就剩一个“内存地址重迭 0x10~0x12”,没找到哪里导致的
回复

使用道具 举报

ID:1077269 发表于 2025-8-19 00:17 | 显示全部楼层
setsu 发表于 2025-8-18 16:24
目前我把一些编译报错都给改了,现在就剩一个“内存地址重迭 0x10~0x12”,没找到哪里导致的

这是这颗IC的规格书0x10~0x12重迭,可是这不是通用寄存器吗?

NY8A051H_v2.0_SC.pdf

1.89 MB, 下载次数: 0

回复

使用道具 举报

ID:1073939 发表于 2025-8-19 08:39 | 显示全部楼层
setsu 发表于 2025-8-18 11:12
#define light_set(x)             \
        do                           \
        {              ...

改成这样
  1. #define light_set(x)             \
  2.         do                           \
  3.         {                            \
  4.                 PORTB &= 0xf1;           \
  5.                 PORTB |= ((x) & 7) << 1; \
  6.         } while (0)
复制代码
回复

使用道具 举报

ID:1073939 发表于 2025-8-19 08:42 | 显示全部楼层
setsu 发表于 2025-8-18 11:19
case 1: // 灯1亮 2秒,接着灯2亮 2秒,灯3亮 2秒
                if (ModCnt == 0 || ModCnt >= 600 ...

应该是上一个错误所致。light_set(x) 的定义改了就好
回复

使用道具 举报

ID:1073939 发表于 2025-8-19 08:47 | 显示全部楼层
setsu 发表于 2025-8-18 16:24
目前我把一些编译报错都给改了,现在就剩一个“内存地址重迭 0x10~0x12”,没找到哪里导致的

把代码中的临时变量改成全局变量试试。这款芯片象微芯的,对C语言支持不够。
回复

使用道具 举报

ID:1073939 发表于 2025-8-19 08:50 | 显示全部楼层
setsu 发表于 2025-8-19 00:17
这是这颗IC的规格书0x10~0x12重迭,可是这不是通用寄存器吗?

组织下全局变量顺序,16bit变量在前面,8bit变量安排在后面。
  1. unchar myvar; // 九齐单片机位定义,将一个char拆成8个bit变量
  2. __sbit key = PORTB : 0;
  3. __sbit light1 = PORTB : 1;
  4. __sbit light2 = PORTB : 2;
  5. __sbit light3 = PORTB : 4;
  6. #define light_get() (((PORTB >> 1) & 7) ? 1 : 0)
  7. #define light_set(x)             \
  8.         do                           \
  9.         {                            \
  10.                 PORTB &= 0xf1;           \
  11.                 PORTB |= ((x) & 7) << 1; \
  12.         } while (0)(PORTB |= 0x1 << x)

  13. unint Mod = 3;
  14. unint ModCnt = 0; // 计时,每10mS加1

  15. unchar keyFlag = 0;
  16. unchar keyCnt = 0; // 计时,每10mS加1

  17. unint sleepCnt = 0; // 计时,每10mS加1
复制代码
回复

使用道具 举报

ID:1077269 发表于 2025-8-22 01:15 | 显示全部楼层
ydatou 发表于 2025-8-19 08:50
组织下全局变量顺序,16bit变量在前面,8bit变量安排在后面。

不行啊,一直提示内存地址重迭0x10~0x12,这是什么原因导致的?
回复

使用道具 举报

ID:1073939 发表于 2025-8-22 14:29 | 显示全部楼层
你这问题应该是九齐mcu特有的,要去找九齐的fae咨询。
回复

使用道具 举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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