[技术支持] HC18M121B1单片机编程问题

[复制链接]
1384|13
poxiao0822 发表于 2025-10-21 22:28 | 显示全部楼层 |阅读模式
C语言编程,在主程序下方写了两个中断程序,INT0和Term1,用IDE软件编译报错,说是在同一优先级,请问什么原因,怎么解决 9278568f79877e33df.png
sunjd 发表于 2025-10-22 11:03 | 显示全部楼层
HC18M121B1单片机只有一个中断向量地址(0008H),这意味着所有中断都共享同一个入口点,不能像某些单片机那样为每个中断单独编写中断服务函数,从数据手册第11页可以看到:
复位向量是0000H
中断向量是0008H(只有一个!)
这意味着所有中断(INT0、INT1、Timer0、Timer1、Timer2、ADC等)都共用同一个中断入口地址。
你需要将两个中断服务程序合并为一个统一的中断服务函数,然后在其中判断具体是哪个中断源触发的。
为了更好地管理多个中断,建议采用以下结构
void interrupt ISR(void)
{
    // 按优先级检查各个中断标志
    if(INT1F) {
        INT1F = 0;
        INT1_Handler();
    }
    else if(T1IF) {
        T1IF = 0;
        Timer1_Handler();
    }
    else if(INT0F) {
        INT0F = 0;
        INT0_Handler();
    }
    // ... 其他中断
}

// 各个中断的具体处理函数
void INT1_Handler(void)
{
    intpwmcount++;
    // INT1具体处理代码
}

void Timer1_Handler(void)
{
    count++;
    // Timer1具体处理代码
}

评论

解释的很到位。  发表于 2025-10-22 13:25
 楼主| poxiao0822 发表于 2025-10-22 22:46 | 显示全部楼层
感谢回复,问题已解决
再请教下,我在做PWM信号检测,方法是外部中断设置边沿触发,通过计数到一定数量,判断有PWM信号输入,但是检测的PWM信号周期为1us,占空比可能很大,也可能很小,致使IO口无法检测到边沿触发,这个单片机FCU为4MHz,想问下需要怎么解决,或者有没更好的PWM检测方法
sunjd 发表于 2025-10-23 17:31 | 显示全部楼层
试试定时器输入捕捉功能
根据数据手册看,Timer1和Timer2都有外部时钟输入功能
// 使用Timer1作为PWM周期测量
void PWM_Detection_Init(void)
{
    // 配置Timer1为外部计数器模式
    T1CON = 0b00011000;  // T1CK[1:0]=10, T1CKI上升沿计数
    T1EN = 1;            // 使能Timer1
   
    // 配置Timer0作为时间基准
    OPTION = 0b00000111; // 预分频给Timer0,1:256
    T0IE = 1;            // 使能Timer0中断
}

// Timer0中断用于定期读取Timer1计数值
void interrupt ISR(void)
{
    if(T0IF)
    {
        T0IF = 0;
        static unsigned int last_count = 0;
        unsigned int current_count = T1;
        
        // 计算频率 = (current_count - last_count) / 定时时间
        unsigned int pulse_count = current_count - last_count;
        last_count = current_count;
        
        // 根据脉冲计数计算PWM频率
        if(pulse_count > 0) {
            // 检测到有效PWM信号
        }
    }
}
 楼主| poxiao0822 发表于 2025-10-25 13:40 | 显示全部楼层
是否可以用T0做外部计数器模式,看数据手册,这个计数器不需要EN吗
sunjd 发表于 2025-10-27 09:12 | 显示全部楼层
HC18M121B1 的 Timer0 可以用作外部计数器,并且它不需要一个独立的“ENABLE”位。通过将 OPTION寄存器的 T0CS 位设置为 1(选择外部 T0CKI 引脚作为时钟源),就自动启动并“使能”了计数器功能。
 楼主| poxiao0822 发表于 2025-10-27 21:52 | 显示全部楼层
已使用T0做好了PWM边沿计数,我现在要检测上图周期间断的PWM波形,请教如何编程将这种波形识别出来
1.png
 楼主| poxiao0822 发表于 2025-10-27 21:59 | 显示全部楼层
请教大佬分享该单片机C代码
sunjd 发表于 2025-10-28 09:26 | 显示全部楼层
试试这个统计分析法,根据实际的PWM参数调整相关阈值和时间参数。
超时阈值:根据正常PWM周期的2-3倍设置
2. 滤波参数:适当增加确认次数避免误判
3. 缓冲区大小:根据检测灵敏度要求调整
4. 统计窗口:通常8-16个周期比较合适
统计分析方法
typedef struct {
    uint32_t period_buffer[10];  // 周期缓冲区
    uint8_t buffer_index;
    uint32_t avg_period;         // 平均周期
    uint32_t max_period;         // 最大周期
    uint8_t is_interrupted;      // 间断标志
} pwm_analyzer_t;

void analyze_pwm_pattern(pwm_analyzer_t *analyzer, uint32_t new_period)
{
    // 更新缓冲区
    analyzer->period_buffer[analyzer->buffer_index] = new_period;
    analyzer->buffer_index = (analyzer->buffer_index + 1) % 10;
   
    // 计算统计信息
    uint32_t sum = 0;
    analyzer->max_period = 0;
   
    for(int i = 0; i < 10; i++) {
        sum += analyzer->period_buffer[i];
        if(analyzer->period_buffer[i] > analyzer->max_period) {
            analyzer->max_period = analyzer->period_buffer[i];
        }
    }
    analyzer->avg_period = sum / 10;
   
    // 检测间断
    if(analyzer->max_period > (analyzer->avg_period * 3)) {
        if(!analyzer->is_interrupted) {
            analyzer->is_interrupted = 1;
            printf("PWM间断检测到!\n");
        }
    } else {
        if(analyzer->is_interrupted) {
            analyzer->is_interrupted = 0;
            printf("PWM恢复正常!\n");
        }
    }
}
 楼主| poxiao0822 发表于 2025-10-28 22:05 | 显示全部楼层
请问还有其他较为简单的实现方法和代码吗,我处于入门水平。
sunjd 发表于 2025-10-30 08:51 | 显示全部楼层
本帖最后由 sunjd 于 2025-10-30 08:57 编辑

那试试这个Timer0计数 + Timer1定时采样

; 使用Timer1产生固定采样周期(如10ms)
INIT_TIMER1_SAMPLING:
    ; 配置Timer1为定时器模式,10ms中断
    MOVLW   B'00000000'      ; 预分频1:2, Timer1振荡器关闭
    MOVWF   T1CON
   
    ; 设置Timer1重载值(根据系统时钟计算)
    MOVLW   0xXX             ; 高字节
    MOVWF   TMR1H
    MOVLW   0xXX             ; 低字节  
    MOVWF   TMR1L
   
    ; 使能Timer1中断
    BSF     T1CR_AUXR, T1IE
    BSF     INTCON, GIE
    RETURN

; Timer1中断服务程序
T1_INTERRUPT_SERVICE:
    ; 保护现场
    MOVWF   W_TEMP
    SWAPF   STATUS, W
    MOVWF   STATUS_TEMP
   
    ; 调用PWM检测函数
    CALL    CHECK_PWM_SIGNAL
   
    ; 清除Timer1中断标志
    BCF     T1CR_AUXR, T1IF
   
    ; 重载Timer1(如果需要)
    MOVLW   0xXX
    MOVWF   TMR1H
    MOVLW   0xXX  
    MOVWF   TMR1L
   
    ; 恢复现场
    SWAPF   STATUS_TEMP, W
    MOVWF   STATUS
    SWAPF   W_TEMP, F
    SWAPF   W_TEMP, W
    RETFIE

sunjd 发表于 2025-10-30 08:59 | 显示全部楼层
防抖动时间:NO_SIGNAL_CNT的阈值(建议3-5次)
采样周期:Timer1中断周期(10-50ms为宜)
PWM存在阈值:最小边沿计数阈值
测量时间:频率测量时的窗口时间
 楼主| poxiao0822 发表于 2025-10-30 22:58 | 显示全部楼层
这个是汇编语言吗,C语言怎么编程
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

10

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部