单片机/MCU论坛
直播中

陈晟

2年用户 18经验值
擅长:嵌入式技术 EDA/IC设计
私信 关注
[问答]

MC68HC908QT4输入捕获问题

使用MC68HC908QT4去控制TCS3200感光传感器,在输入捕获中卡住了,不知道为什么一直处于捕获中,不能执行主程序内容,代码如下
image.png
image.png
image.png

望大佬们指教

已退回20积分

回帖(2)

陈晟

2025-3-5 17:41:21
#include
#include "stdlib.h"
#include
#include
#include "derivative.h"
#pragma LINK_INFO DERIVATIVE "MC68HC908QT4"

// --------------------- 系统配置 ---------------------
#define SYS_CLK        3200000UL    // 系统时钟3.2MHz
#define PWM_PRESCALER  4            // PWM分频系数(定时器时钟=800kHz)
#define FILTER_DELAY   100           // 滤波器切换后稳定时间(ms)
//#define uint16  unsigned int
#define uint8  unsigned char
#define uint16 unsigned short     int
  #define  uint32   unsigned long int   
#define max(x,y) ((x) > (y) ? (x) :(y))
#define min(x,y) ((x) < (y) ? (x) : (y))

// --------------------- 数据结构定义 ---------------------
typedef struct {
    volatile uint16 r;  // 红色通道频率
    volatile uint16 g;  // 绿色通道频率
    volatile uint16 b;  // 蓝色通道频率
} RGB_Data;

typedef struct {
    uint8 r;  // 红色通道(0-255)
    uint8 g;  // 绿色通道(0-255)
    uint8 b;  // 蓝色通道(0-255)
} RGB_8Bit;



typedef struct{
        unsigned int h;       //[0,360]
        unsigned char  s;       //[0,100]
        unsigned char  l;       //[0,100]
}COLOR_HSL;//HSL

typedef struct {
    float lower_hue;
    float upper_hue;
    const char* color_name;
} ColorRange;



// --------------------- TCS3200控制参数 ---------------------
typedef enum {
    TCS_FILTER_RED    = 0,  // S2=0, S3=0 → 红色滤波器
    TCS_FILTER_BLUE   = 1,  // S2=1, S3=0 → 蓝色滤波器
    TCS_FILTER_GREEN  = 2,  // S2=0, S3=1 → 绿色滤波器
    TCS_FILTER_CLEAR  = 3   // S2=1, S3=1 → 无滤波器
} TCS_ColorFilter;

// --------------------- 全局变量 ---------------------
volatile uint16 g_pulse_count = 0;  // 脉冲计数器
volatile uint8 g_current_filter = 0; // 当前滤波器:0-Red,1-Green,2-Blue
RGB_8Bit g_rgb_8bit; // 存储归一化后的RGB值
RGB_Data g_rgb;          // 存储RGB测量结果
COLOR_HSL  hsl;        //HSL
volatile uint16 g_pwm_freq = 5200;  // PWM目标频率(默认1kHz)

ColorRange color_ranges[] = {
    {0, 15, "Red"},
    {15, 30, "Red-Orange"},
    {30, 45, "Orange"},
    {45, 60, "Yellow-Orange"},
    {60, 75, "Yellow"},
    {75, 90, "Yellow-Green"},
    {90, 150, "Green"},
    {150, 180, "Blue-Green"},
    {180, 210, "Cyan"},
    {210, 240, "Indigo"},
    {240, 270, "Blue"},
    {270, 300, "Magenta"},
    {300, 330, "Purple-Red"},
    {330, 360, "Red"}  // 共14项
};
// --------------------- 函数声明 ---------------------
void SystemInit(void);
void TCS3200_Init(void);
void TCS3200_SetFilter(TCS_ColorFilter filter);
void PWM_Init(uint16 freq);
void InputCapture_Init(void);
void Read_RGB(void);
uint16 Measure_Frequency(void);
void Set_PWM_Freq(uint16 target_freq);
void Delay_ms(uint16 ms);
void  RGBtoHSL(RGB_Data *Rgb, COLOR_HSL *Hsl);
void judgeColor(RGB_Data *Rgb) ;

    uint8 flag =0 ;
// ===================== 中断服务程序 =====================
#pragma CODE_SEG __NEAR_SEG NON_BANKED
// 输入捕获中断(统计脉冲)
void interrupt 5 TCH1_ISR(void) {
    if(TSC1 & 0x80) {             // 检测到上升沿
          flag = 1;
  //      g_pulse_count++;           // 累加脉冲计数
        TSC1 &= ~0x80;            // 清除捕获标志
    }
}
#pragma CODE_SEG DEFAULT




/******************** 主程序 ********************/
void main(void)
{

   
    SystemInit();         // 系统初始化
    TCS3200_Init();      // 初始化TCS3200
    PWM_Init(g_pwm_freq); // 初始化PWM(默认1kHz)
    InputCapture_Init(); // 初始化输入捕获


   
    for(;;) {
   //  Read_RGB();      // 更新RGB测量值到g_rgb
        
           if(flag){
             Set_PWM_Freq (1200);}
        // 示例:根据红色通道亮度调整PWM频率
     

    }
}

/******************** RGB测量函数 ********************/
void Read_RGB(void)
{
uint16 current_max;   
    TCS3200_SetFilter(TCS_FILTER_RED);
    g_pulse_count = 0;
    Delay_ms(FILTER_DELAY);
    g_rgb.r = g_pulse_count;

   
        
    TCS3200_SetFilter(TCS_FILTER_GREEN);
    g_pulse_count = 0;
    Delay_ms(FILTER_DELAY);
    g_rgb.g = g_pulse_count;
  
     
    TCS3200_SetFilter(TCS_FILTER_BLUE);
    g_pulse_count = 0;
    Delay_ms(FILTER_DELAY);
    g_rgb.b = g_pulse_count;
   
   current_max  = max(g_rgb.r, max(g_rgb.g, g_rgb.b));
    if (current_max == 0) current_max = 1; // 避免除以零

    // 计算各通道的8位值
    g_rgb_8bit.r = (uint8)(((uint32)g_rgb.r * 255) / current_max);
    g_rgb_8bit.g = (uint8)(((uint32)g_rgb.g * 255) / current_max);
    g_rgb_8bit.b = (uint8)(((uint32)g_rgb.b * 255) / current_max);
  
}

/******************** TCS3200控制函数 ********************/
void TCS3200_Init(void)
{
    DDRA |= 0x30;        // PA4(S2)、PA5(S3)设为输出
    PTA &= ~0x30;      // 初始状态:红色滤波器
}

void TCS3200_SetFilter(TCS_ColorFilter filter)
{
    switch(filter) {
        case TCS_FILTER_RED:    PTA = (PTA & ~0x30) | 0x00; break;
        case TCS_FILTER_BLUE:   PTA = (PTA & ~0x30) | 0x20; break;
        case TCS_FILTER_GREEN:  PTA = (PTA & ~0x30) | 0x30; break;
        case TCS_FILTER_CLEAR:  PTA = (PTA & ~0x30) | 0x10; break;
    }
}

void PWM_Init(uint16 freq)
{
     uint16  tmod;
    // 配置PA0为PWM输出(TCH0功能)
    DDRA |= 0x01;        // PA0设为输出

    // 计算周期和比较值(占空比50%)
   
     tmod = (SYS_CLK / (PWM_PRESCALER * freq)) - 1;
    TMODH = (tmod >> 8) & 0xFF;
    TMODL = tmod & 0xFF;
    TCH0H = (tmod / 2) >> 8;
    TCH0L = (tmod / 2) & 0xFF;

    // 定时器通道0配置:输出比较,翻转电平
    TSC0 = 0x16;         // TOV=0, CHMAX=0, MS0A=1, ELS0=2(翻转模式)
    TSC = 0x02;          // 分频4,启动定时器
}
/******************** PWM输出函数(PA0引脚) ********************/


void Set_PWM_Freq(uint16 target_freq)
{
     uint16  tmod;
     tmod = (SYS_CLK / (PWM_PRESCALER * target_freq)) - 1;
    DisableInterrupts;
    TMODH = (tmod >> 8) & 0xFF;
    TMODL = tmod & 0xFF;
    TCH0H = (tmod / 2) >> 8;
    TCH0L = (tmod / 2) & 0xFF;
    EnableInterrupts;
}

/******************** 输入捕获函数(PA1引脚) ********************/
void InputCapture_Init(void)
{
    DDRA &= ~0x02;       // PA1设为输入(TCS3200 OUT)
    TSC1 = 0x44;         // 输入捕获,上升沿触发
    TSC |= 0x02;         // 分频4(与PWM共用定时器)
}



/******************** 系统初始化函数 ********************/
void SystemInit(void)
{
    OSCTRIM = *(uint8*)0xFFC0;  // 时钟微调
    CONFIG1 = 0x00;             // 关闭看门狗
    CONFIG2 = 0x40;             // 启用IRQ中断
}

/******************** 简单延时函数 ********************/
void Delay_ms(uint16 ms)
{
    uint16 i,j;
    for( i=0; ir, Rgb->g), Rgb->b);
         int rgbMin = min(min(Rgb->r, Rgb->g), Rgb->b);
//        printf("\n Rgb->r, Rgb->g, Rgb->b =%d =%d =%d\n ",Rgb->r, Rgb->g, Rgb->b);  
        int temp,temp2;
        //hue[flatten]
       
    temp2=(rgbMax - rgbMin);
       
        if (abs(rgbMax - rgbMin) < precision) // max == min
        {
                Hsl->h = 0;
        }
        else if (abs(rgbMax - Rgb->r) < precision) // max == r
        {
                temp = Rgb->g - Rgb->b;// / (rgbMax - rgbMin);
                temp*=60;               
                temp/=temp2;
                if (Rgb->g < Rgb->b)
                temp += 360;
                Hsl->h=(uint16)temp;
        }
        else if (abs(rgbMax - Rgb->g) < precision) // max == g
        {
                temp=Rgb->b - Rgb->r;
                temp*=60;
            temp/=temp2;
                temp += 120;
                Hsl->h=(uint16)temp;
                //Hsl->h = 60 * (Rgb->b - Rgb->r) / (rgbMax - rgbMin) + 120;
        }
        else if (abs(rgbMax - Rgb->b) < precision) // max == b
        {
                temp=Rgb->r - Rgb->g;
                temp*=60;
                temp/=temp2;
                temp += 240;
                Hsl->h=(uint16)temp;
                //Hsl->h = 60 * (Rgb->r - Rgb->g) / (rgbMax - rgbMin) + 240;
        }
        // light
        temp= (rgbMax + rgbMin) / 2;
        Hsl->l=(uint8)temp;
        // saturation

        if (temp <= precision || abs(rgbMax - rgbMin) < precision)
        {
                Hsl->s = 0;
        }
        else if (temp > 0 && temp <= 0.5)
        {               
                temp=rgbMax - rgbMin;
                temp2=rgbMax + rgbMin;
                temp/=temp2;
                Hsl->s=(uint16)temp;               
                //Hsl->s = (rgbMax - rgbMin) / (rgbMax + rgbMin);
        }
        else if (temp > 0.5)
        {
                temp=rgbMax - rgbMin;
                temp*=100;
                temp2=rgbMax + rgbMin;
                temp2=510-temp2;
                temp/=temp2;
                Hsl->s=(uint16)temp;
                //Hsl->s = (rgbMax - rgbMin) / (2 - (rgbMax + rgbMin));
        }

}




                                                      
// 2. 修正函数实现
void judgeColor(RGB_Data *Rgb)
{               
                unsigned int ColorVoltage[16]={12000,11000,10000,9000,9500,8500,8000,7000,6500,6000,5000,4000,3000,2500,2000,12000};

     int num_ranges,i;
                RGBtoHSL(&Rgb, &hsl);
                // Define the color range array
    num_ranges= sizeof(color_ranges) / sizeof(ColorRange);

   
          for ( i = 0; i < num_ranges; i++)
          {
            if (hsl.h >= color_ranges[i].lower_hue && hsl.h < color_ranges[i].upper_hue)
            {
            
                //输出频率
                    Set_PWM_Freq(ColorVoltage[i] );
            }
        }

}
完整代码如上
举报

温暖镜头

2025-3-5 17:57:56

在使用MC68HC908QT4微控制器控制TCS3200感光传感器时,如果输入捕获功能卡住,导致主程序无法继续执行,可能是由于以下几个原因导致的。我们可以通过检查代码和硬件配置来逐步排查问题。


1. 输入捕获配置问题


首先,确保输入捕获功能的配置是正确的。MC68HC908QT4的输入捕获功能通常通过定时器模块(Timer)来实现。你需要确保定时器的输入捕获通道已经正确配置,并且中断已经启用。


// 假设使用Timer1的通道0进行输入捕获
void Init_InputCapture(void) {
    T1SC = 0x00;        // 停止定时器
    T1SC_TOF = 0;       // 清除定时器溢出标志
    T1SC_TOIE = 0;      // 禁用定时器溢出中断
    T1SC_TCRE = 1;      // 使能定时器计数器复位
    T1SC_TSTOP = 0;     // 启动定时器

    T1SC0 = 0x04;       // 配置为输入捕获模式,上升沿触发
    T1SC0_ICIE = 1;     // 使能输入捕获中断
}

2. 中断服务程序问题


输入捕获中断服务程序(ISR)需要正确处理捕获事件,并清除中断标志。如果中断标志没有清除,中断会一直触发,导致程序卡在中断服务程序中。


#pragma interrupt_handler T1CH0_ISR
void T1CH0_ISR(void) {
    // 处理捕获事件
    uint16_t capture_value = T1CH0;  // 读取捕获值

    // 清除中断标志
    T1SC0_ICF = 1;

    // 其他处理逻辑
}

3. 主程序逻辑问题


确保主程序逻辑不会因为等待输入捕获事件而卡住。如果主程序中有等待输入捕获事件的循环,可能会导致程序无法继续执行。


void main(void) {
    Init_InputCapture();  // 初始化输入捕获

    while (1) {
        // 主程序逻辑
        // 不要在这里等待输入捕获事件
    }
}

4. 硬件连接问题


检查TCS3200传感器与MC68HC908QT4的硬件连接是否正确。确保传感器的输出信号正确连接到微控制器的输入捕获引脚,并且信号电平符合微控制器的输入要求。


5. 调试和验证


使用调试工具(如仿真器或逻辑分析仪)来验证输入捕获信号是否正常,并且中断是否被正确触发。通过调试工具可以更直观地发现问题所在。


示例代码


以下是一个简单的示例代码,展示了如何配置和使用输入捕获功能:


#include           // 包含MC68HC908QT4的头文件

void Init_InputCapture(void) {
    T1SC = 0x00;        // 停止定时器
    T1SC_TOF = 0;       // 清除定时器溢出标志
    T1SC_TOIE = 0;      // 禁用定时器溢出中断
    T1SC_TCRE = 1;      // 使能定时器计数器复位
    T1SC_TSTOP = 0;     // 启动定时器

    T1SC0 = 0x04;       // 配置为输入捕获模式,上升沿触发
    T1SC0_ICIE = 1;     // 使能输入捕获中断
}

#pragma interrupt_handler T1CH0_ISR
void T1CH0_ISR(void) {
    // 处理捕获事件
    uint16_t capture_value = T1CH0;  // 读取捕获值

    // 清除中断标志
    T1SC0_ICF = 1;

    // 其他处理逻辑
}

void main(void) {
    Init_InputCapture();  // 初始化输入捕获

    EnableInterrupts;    // 使能全局中断

    while (1) {
        // 主程序逻辑
        // 不要在这里等待输入捕获事件
    }
}

总结


通过检查输入捕获的配置、中断服务程序、主程序逻辑以及硬件连接,应该能够找到问题所在并解决。如果问题仍然存在,建议使用调试工具进一步分析。

1 举报
  • 陈晟: 该寄存器配置都是错误的

更多回帖

发帖
×
20
完善资料,
赚取积分