时间码发生器通过两条线与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]) {</i>
- <span style="font-style: italic;"> uint16_t tmp = LtcInput.tim;
- LtcInput.tim<i style="font-style: italic;"> = LtcInput.tim[j];
- LtcInput.tim[j] = tmp;
- </i><span style="font-style: normal;">}
- }
- }
- 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);
- }
- }</span></span>
复制代码
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<span style="font-style: italic;"><span style="font-style: normal;"> >>= nbits;
- raw</span><span style="font-style: normal;"> += tmp;
- }
- raw</span><span style="font-style: normal;"> >>= 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</span><span style="font-style: normal;"> & 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</span><span style="font-style: normal;"> = 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</span><span style="font-style: normal;"> = 0;
- for(j=0; j<8; j++) {
- tmp2 = tmp & (3 << j*2);
- tmp2 >>= j*2;
- if((0 != tmp2) && (3 != tmp2)) {
- dst</span><span style="font-style: normal;"> |= (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</span><span style="font-style: normal;">, 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;
- }
- }
- }
- </span></span>
复制代码
总结以及调试过程中发现的问题。
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 */
- }
复制代码
|