STM32G070 定时器中断接收时间码

时间码发生器通过两条线与MCU相连,一条是地,一条是信号线用于传输数据。信号传输使用差分曼彻斯特编码。电平±1.5V, 信号传输的速率960Hz 到 2400Hz 变化,需要软件自动适配。 时间码固定为80bit数据(bit0~bit79), 其中bit64~bit79 为同步码,固定为0011 1111 1111 1101。 部分波形如下图,

 

实现原理,

1.  EXTI  Rising/Falling 中断+定时器方式测量100次波形脉冲宽度,通过排序算法找到合适的值确定为定时器周期值Period

2.  继续用EXTI  Rising/Falling 中断+定时器方式接收时间码0101值, EXTI  Rising/Falling 中断时,修正定时器中断周期为Period/2。

产生定时器中断之后,取Pin 值保存,修正定时器中断周期为Period

3.  解析差分曼切斯特编码,查找同步码

 

流程图,

 

关键过程代码,

1. EXIT 中断处理

struct LtcInput_s LtcInput = {
    .tim = {0},
    .tim_count = 0,
    .period = 0xffff,
};

static uint16_t parse_tim_of_ltc_input_get_period(void)
{
    for (int i = 0; i < LTC_INPUT_BUF_SIZE; ++i) {
        for (int j = i; j < LTC_INPUT_BUF_SIZE; ++j) {
            if(LtcInput.tim[i] > LtcInput.tim[j]) {
                uint16_t tmp = LtcInput.tim[i];
                LtcInput.tim[i] = LtcInput.tim[j];
                LtcInput.tim[j] = tmp;
            }
        }
    }
    uint16_t period = LtcInput.tim[10];
    return period;
}

void ltc_input_timer_restart(int period)
{
  
  htim3.Instance->SR = 0;
 htim3.Instance->ARR = period;
 htim3.Instance->CNT = 0;

}

void ltc_input_pin_callback(void)
{
    // HAL_TIM_Base_Stop_IT(&htim3);
    if(LtcInput.tim_count >= LTC_INPUT_BUF_SIZE) {
        ltc_input_timer_restart(LtcInput.period/2);
    } else {
        LtcInput.tim[LtcInput.tim_count] = htim3.Instance->CNT;
        LtcInput.tim_count++;
        if(LtcInput.tim_count >= LTC_INPUT_BUF_SIZE) {
            LtcInput.period = parse_tim_of_ltc_input_get_period();
        }
        ltc_input_timer_restart(0xffff);
    }
}

2. 定时器处理


/**
  * @brief This function handles TIM3 global interrupt.
  */
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_GPIO_TogglePin(TEST1_GPIO_Port, TEST1_Pin);
  htim3.Instance->SR = 0;
  htim3.Instance->ARR = LtcInput.period;
  htim3.Instance->CNT = 0;
  ltc_input_timer_callback();
  
  /* USER CODE END TIM3_IRQn 1 */
}

char ltc_input_timer_callback(void)
{
    GPIO_PinState status;
    unsigned char x, y;

    status = HAL_GPIO_ReadPin(LTC_INPUT_GPIO_Port, LTC_INPUT_Pin);
    //status = GPIO_ReadInputDataBit(LTC_PORT, LTC_PIN);
    //HAL_GPIO_TogglePin(TEST1_GPIO_Port, TEST1_Pin);

    //GPIO_WriteBit(TEST_PORT, TEST_PIN, status);
    //GPIO_WriteBit(TEST_PORT, TEST_PIN, SET);
    //move_right_linear_timecode_raw(linear_timecode_raw, sizeof(linear_timecode_raw));

    x = linear_timecode_count /8;
    y = linear_timecode_count %8;

    //buf[linear_timecode_count] = status;
    linear_timecode_raw[x] &= ~(1 << y);

    if(status != GPIO_PIN_RESET) {
        linear_timecode_raw[x] |= (1 << y);
    }

    linear_timecode_count ++;

    if(linear_timecode_status == LTC_STATUS_NEED_FIND_SYNC) {
        if(linear_timecode_count >= sizeof(linear_timecode_raw) * 8) {
            linear_timecode_count =0;
            memcpy(linear_timecode_raw_ready, linear_timecode_raw, sizeof(linear_timecode_raw));
            linear_timecode_ready = 1;
        }
    } else {
        if(offset_bits > 0) {
            //skip offset_bits
            //If offset < linear_timecode_count, adjust the offset to the next frame.
            //Next time, when count = offset, the counter is cleared. From then on, each frame starts from scratch.
            if(linear_timecode_count > offset_bits) {
                 offset_bits += 160;
            } else if(linear_timecode_count == offset_bits) {
                offset_bits = 0;
                linear_timecode_count = 0;
            }
        } else {
            if(linear_timecode_count >= sizeof(linear_timecode_raw) * 8 / 2) {
                linear_timecode_count =0;
                memcpy(linear_timecode_raw_ready, linear_timecode_raw, sizeof(linear_timecode_raw) / 2);
                linear_timecode_ready = 1;
            }
        }
    }
    return 0;
}

3.  差分曼切斯特码解码


unsigned char r_mask[] = {0x0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
unsigned char l_mask[] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };

static void move_right_linear_timecode_raw_7bits(unsigned char *raw, unsigned char nbytes, unsigned char nbits)
{
    unsigned char i;
    unsigned char tmp;

    if((nbits < 1) || (nbits > 7)) {
        return;
    }

    for(i=0; i<nbytes - 1; i++) {
        tmp = raw[i+1] & r_mask[nbits];
        tmp <<= (8-nbits);
        raw[i] >>= nbits;
        raw[i] += tmp;
    }
    raw[i] >>= nbits;
}

static void move_left_linear_timecode_raw_7bits(unsigned char *raw, unsigned char nbytes, unsigned char nbits)
{
    unsigned char i;
    unsigned char tmp;

    if((nbits < 1) || (nbits > 7)) {
        return;
    }

    for(i=0; i<nbytes - 1; i++) {
        //prev_bit = raw[i] & 0x80;
        tmp = raw[nbytes - i - 2] & l_mask[nbits];
        raw[nbytes - i -1] <<= nbits;
        tmp >>= (8-nbits);
        raw[nbytes - i -1] += tmp;
    }
    raw[0] <<= nbits;
}

static void move_right_linear_timecode_raw_nbits(unsigned char *raw, unsigned char nbytes, unsigned short nbits)
{
    unsigned char x, y;

    x = nbits / 8;
    y = nbits % 8;

    if(x > 0) {
        for (int i = 0; i < nbytes ; i++) {
            raw[i] = raw[x+i];
        }
    }
    move_right_linear_timecode_raw_7bits(raw, nbytes, y);
}


static void move_left_linear_timecode_raw_nbits(unsigned char *raw, unsigned char nbytes, unsigned short nbits)
{
    unsigned char x, y;

    x = nbits / 8;
    y = nbits % 8;

    if(x > 0) {
        for (int i = 0; i < nbytes ; i++) {
            raw[nbytes-i-1] = raw[nbytes-i-1-x];
        }
    }
    move_left_linear_timecode_raw_7bits(raw, nbytes, y);
}

unsigned char get_bit_linear_timecode_raw(unsigned char index)
{
    unsigned char x = index/8;
    unsigned char y = index%8;

    if(linear_timecode_raw[x] & (1 <<y))
        return 1;
    else
        return 0;
}

static void parse_differential_manchester_code(unsigned char *src,  unsigned char *dst, unsigned char dst_size)
{
    unsigned char i, j;
    unsigned short tmp, tmp2;

    for(i=0; i<dst_size; i++) {

        tmp = (src[i*2 +1] << 8) + src[i*2];
        dst[i] = 0;
        for(j=0; j<8; j++) {
            tmp2 = tmp & (3 << j*2);
            tmp2 >>= j*2;
            if((0 != tmp2) && (3 != tmp2)) {
                dst[i] |= (1<<j);
            }
        }
    }
}

static char find_sync_code(unsigned char *src, unsigned char len, unsigned char *dst, unsigned char *valid_len)
{
    const unsigned short sync_code = 0xFCBF;
    unsigned char i;
    unsigned short tmp;
    char ret=-1;

    for (i=0; i<len-8; i++) {
        tmp = (src[i+8] << 8) + src[i+9];
        if (tmp == sync_code) {
            ret =0;
            *valid_len = len - i;
            memcpy(dst, &src[i], 10);   //10Bytes equals 80bits
            break;
        }
    }

    return ret;

}

unsigned char ltc_dst_code[40][10]= {0};
unsigned char ltc_dst_code_count = 0;
unsigned char ltc_code_valid_len=0;
unsigned char ltc_code[20] = {0};
unsigned char raw_ready[60] = {0};
unsigned short offset_bits = 0;
unsigned short ltc_remain_bits = 0;
unsigned char sec_ltc_code[20] = {0};
unsigned char ltc_dst_code_cur[10]= {0};
unsigned char new_frame =0;


void parse_linear_timecode_raw()
{
    unsigned char tmp;
    unsigned char raw_mv_right_bits = 0;

    if(linear_timecode_status == LTC_STATUS_NEED_FIND_SYNC) {
        isjam = 0;
        memcpy(raw_ready, linear_timecode_raw_ready, sizeof(linear_timecode_raw_ready));
        tmp = raw_ready[0] & 0x03;
        while((0 != tmp) && (3 != tmp)) {
            move_right_linear_timecode_raw_nbits(raw_ready, sizeof(raw_ready), 1);
            raw_mv_right_bits ++;
            tmp = raw_ready[0] & 0x03;
        }

        for (int i = 0; i < sizeof(linear_timecode_raw_ready)*8; ++i) {
            memset(ltc_code, 0 , sizeof(ltc_code));
            parse_differential_manchester_code(raw_ready,  ltc_code, sizeof(ltc_code));
            //0xFCBF;
            if((ltc_code[8] == 0xFC)&&(ltc_code[9]==0xBF)) {
                linear_timecode_status = !LTC_STATUS_NEED_FIND_SYNC;
                offset_bits = raw_mv_right_bits;
                break;
            }
            move_right_linear_timecode_raw_nbits(raw_ready, sizeof(raw_ready), 1);
            raw_mv_right_bits ++;
        }

        if(linear_timecode_status == LTC_STATUS_NEED_FIND_SYNC) {
            LtcInput.tim_count = 0;     //reflesh tim2 period
        }

    } else {
        isjam = 1;
        memcpy(ltc_code, linear_timecode_raw_ready, sizeof(ltc_code));
        parse_differential_manchester_code(ltc_code,  ltc_dst_code_cur, sizeof(ltc_dst_code_cur));
        if((ltc_dst_code_cur[8] != 0xFC)||(ltc_dst_code_cur[9]!=0xBF)) {
            linear_timecode_status = LTC_STATUS_NEED_FIND_SYNC;
            LtcInput.tim_count = 0;     //reflesh tim2 period
        } else {
            new_frame =1;
        }
    }
}

 

总结以及调试过程中发现的问题。

1. 测量周期,比较顺利, 56MHz , 测量出脉冲周期202 us

2. 采样过程中,发现定时器中断,在修正过程中, 出现中断异常,增加调试口翻转看波形

异常1, 中断回调,里面调用HAL_TIM_xxx ,  导致反复进入定时器中断,

异常2, 定时器停止-> 修改周期 -> 定时器启动,每次启动都会中断一下,启动前清中断标志也不行

解决办法,通修改 TIM中断处理程序,直接修改寄存器。 中间不停止,最终得到正确的波形


void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_GPIO_TogglePin(TEST1_GPIO_Port, TEST1_Pin);
  htim3.Instance->SR = 0;
  htim3.Instance->ARR = LtcInput.period;
  htim3.Instance->CNT = 0;
  ltc_input_timer_callback();
  
  /* USER CODE END TIM3_IRQn 1 */
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值