DYyanfa 2024-03-19 14:17 采纳率: 31.3%
浏览 16
已结题

单片机IO口电平翻转异常

使用STC8g1k08芯片编写一个简单的长按按键2秒,对应P15 IO口电平翻转的程序,现在存在如下2个问题:
问题1:按下按键2秒钟后,led灯会高亮,松手后led灯才会熄灭(即:当前led的电平为0,长按按键2秒后led会变亮,当前led电平为1,led点亮,长按按键2秒后,led亮度增加,不松手一直亮,按键松手led熄灭),不清楚为什么led到2秒为什么会高亮?
问题2:按键按下2秒后,led高亮后马上松手,led未马上亮或灭,会保持之前状态。

#include "main.h"

extern char wptr;    
extern char rptr;
extern char buffer[16];


void main()
{
        GPIO_Init();
        P15 = 0;
        P32 = 1;
    UartInit();   //串口初始化
        EA = 1;                 //打开总中断
    ES = 1;         //打开串口中断
        ConfigTimer0();  //定时2ms
    UartSendStr("Uart Test !\r\n");

    while (1)
    {
            KeyDriver(); //按键扫描
            if (rptr != wptr)  //读写指针不等,说明有数据需要发送
        {
            UartSend(buffer[rptr++]);
            rptr &= 0x0f;
        }
            
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
led.c:
#include "Key.h"

sbit PWR_key_det = P3^2;
sbit PWR_HOLD = P1^5;
void ConfigTimer0();
void KeyDriver();
void KeyScan();

unsigned long KeyDownTime = 0;

void  KeyDriver()
{
    if(KeyDownTime > 0)
        {
            if(KeyDownTime >= 1000)
            {
                _nop_();
                _nop_();

                PWR_HOLD = ~PWR_HOLD;  //按下按键2秒,PWR_HOLD状态取反
            }
        }
}

void KeyScan()  //按键扫描函数
{
        static unsigned char keybuf = 0xFF;
        keybuf = (keybuf <<1) |PWR_key_det;
        if(keybuf == 0x00)
        {
            KeyDownTime += 1;//按键按下每次进入中断就加2
        }
        else if(keybuf == 0xFF)
        {
            KeyDownTime = 0;
        }
        else
        {}
}

void ConfigTimer0()
{
    AUXR &= 0x7F;   //2ms定时
    TMOD &= 0xF0;
    TH0 = 0xF8;     
    TL0 = 0xCD;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}

void TM0_Isr() interrupt 1
{
    KeyScan();
    
    TH0 = 0xF8;
    TL0 = 0xCD;
    TF0 = 0;
      
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
GPIO.c

void GPIO_Init()
{
 
        P1M0 = 0x00; 
        P1M1 = 0x00; 
        P3M0 = 0x00; 
        P3M1 = 0x00; 
}

img

  • 写回答

1条回答 默认 最新

  • 码农阿豪@新空间代码工作室 Java领域优质创作者 2024-03-19 14:18
    关注
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    问题1的解答: 问题出在按键按下时的计时器上,如果每次按键按下时都重新开始计时,那么可能会导致在2秒内多次计时器被启动,从而导致计时器溢出,最终导致led灯高亮。解决方法是在计时器开始计时时,先判断计时器是否已经在工作状态,如果已经在工作状态,就不需要再次开始计时。 以下是代码示例: unsigned long KeyDownTime = 0; bit IsTiming = 0; void KeyDriver(){
    if(KeyDownTime > 0 && !IsTiming)
        {
            if(KeyDownTime >= 1000)
            {
                P15 = !P15;
                IsTiming = 1;
            }
        }
    

    } void ConfigTimer0(){ AUXR &= 0x7F; //2ms定时 TMOD &= 0xF0; TH0 = 0xF8;
    TL0 = 0xCD; ET0 = 1; TR0 = 1; } void TM0_Isr() interrupt 1{ KeyScan();
    if(IsTiming){ KeyDownTime = 0; IsTiming = 0; }
    TH0 = 0xF8; TL0 = 0xCD; TF0 = 0; } 问题2的解答: 问题出在按键按下时计时器递增的方式上,每次按键按下时,计时器会加2,而不是加1,导致计时器实际上比预期快了一倍,从而在松手后2秒内,计时器仍然没有达到2秒,所以LED的状态没有变化。 以下是代码示例: void KeyScan() { static unsigned char keybuf = 0xFF; keybuf = (keybuf << 1) |PWR_key_det; if(keybuf == 0x00) { KeyDownTime ++; } else if(keybuf == 0xFF) {
    KeyDownTime = 0; } }

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 4月4日
  • 已采纳回答 3月27日
  • 创建了问题 3月19日

悬赏问题

  • ¥15 怎么把512还原为520格式
  • ¥15 MATLAB的动态模态分解出现错误,以CFX非定常模拟结果为快照
  • ¥15 求高通平台Softsim调试经验
  • ¥15 canal如何实现将mysql多张表(月表)采集入库到目标表中(一张表)?
  • ¥15 wpf ScrollViewer实现冻结左侧宽度w范围内的视图
  • ¥15 栅极驱动低侧烧毁MOSFET
  • ¥30 写segy数据时出错3
  • ¥100 linux下qt运行QCefView demo报错
  • ¥50 F1C100S下的红外解码IR_RX驱动问题
  • ¥20 基于matlab的航迹融合 航迹关联 航迹插补