你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32G070 定时器中断接收时间码

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

20201127093851207.png



实现原理,

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

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

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

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

流程图,

20201127113610958.png



关键过程代码,

1. EXIT 中断处理

  1. struct LtcInput_s LtcInput = {
  2.     .tim = {0},
  3.     .tim_count = 0,
  4.     .period = 0xffff,
  5. };

  6. static uint16_t parse_tim_of_ltc_input_get_period(void)
  7. {
  8.     for (int i = 0; i < LTC_INPUT_BUF_SIZE; ++i) {
  9.         for (int j = i; j < LTC_INPUT_BUF_SIZE; ++j) {
  10.             if(LtcInput.tim<i> > LtcInput.tim[j]) {</i>
  11. <span style="font-style: italic;">                uint16_t tmp = LtcInput.tim;
  12.                 LtcInput.tim<i style="font-style: italic;"> = LtcInput.tim[j];
  13.                 LtcInput.tim[j] = tmp;
  14.             </i><span style="font-style: normal;">}
  15.         }
  16.     }
  17.     uint16_t period = LtcInput.tim[10];
  18.     return period;
  19. }

  20. void ltc_input_timer_restart(int period)
  21. {

  22.   htim3.Instance->SR = 0;
  23. htim3.Instance->ARR = period;
  24. htim3.Instance->CNT = 0;

  25. }

  26. void ltc_input_pin_callback(void)
  27. {
  28.     // HAL_TIM_Base_Stop_IT(&htim3);
  29.     if(LtcInput.tim_count >= LTC_INPUT_BUF_SIZE) {
  30.         ltc_input_timer_restart(LtcInput.period/2);
  31.     } else {
  32.         LtcInput.tim[LtcInput.tim_count] = htim3.Instance->CNT;
  33.         LtcInput.tim_count++;
  34.         if(LtcInput.tim_count >= LTC_INPUT_BUF_SIZE) {
  35.             LtcInput.period = parse_tim_of_ltc_input_get_period();
  36.         }
  37.         ltc_input_timer_restart(0xffff);
  38.     }
  39. }</span></span>
复制代码

2. 定时器处理
  1. /**
  2.   * @brief This function handles TIM3 global interrupt.
  3.   */
  4. void TIM3_IRQHandler(void)
  5. {
  6.   /* USER CODE BEGIN TIM3_IRQn 0 */

  7.   /* USER CODE END TIM3_IRQn 0 */
  8.   HAL_GPIO_TogglePin(TEST1_GPIO_Port, TEST1_Pin);
  9.   htim3.Instance->SR = 0;
  10.   htim3.Instance->ARR = LtcInput.period;
  11.   htim3.Instance->CNT = 0;
  12.   ltc_input_timer_callback();

  13.   /* USER CODE END TIM3_IRQn 1 */
  14. }

  15. char ltc_input_timer_callback(void)
  16. {
  17.     GPIO_PinState status;
  18.     unsigned char x, y;

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

  22.     //GPIO_WriteBit(TEST_PORT, TEST_PIN, status);
  23.     //GPIO_WriteBit(TEST_PORT, TEST_PIN, SET);
  24.     //move_right_linear_timecode_raw(linear_timecode_raw, sizeof(linear_timecode_raw));

  25.     x = linear_timecode_count /8;
  26.     y = linear_timecode_count %8;

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

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

  32.     linear_timecode_count ++;

  33.     if(linear_timecode_status == LTC_STATUS_NEED_FIND_SYNC) {
  34.         if(linear_timecode_count >= sizeof(linear_timecode_raw) * 8) {
  35.             linear_timecode_count =0;
  36.             memcpy(linear_timecode_raw_ready, linear_timecode_raw, sizeof(linear_timecode_raw));
  37.             linear_timecode_ready = 1;
  38.         }
  39.     } else {
  40.         if(offset_bits > 0) {
  41.             //skip offset_bits
  42.             //If offset < linear_timecode_count, adjust the offset to the next frame.
  43.             //Next time, when count = offset, the counter is cleared. From then on, each frame starts from scratch.
  44.             if(linear_timecode_count > offset_bits) {
  45.                  offset_bits += 160;
  46.             } else if(linear_timecode_count == offset_bits) {
  47.                 offset_bits = 0;
  48.                 linear_timecode_count = 0;
  49.             }
  50.         } else {
  51.             if(linear_timecode_count >= sizeof(linear_timecode_raw) * 8 / 2) {
  52.                 linear_timecode_count =0;
  53.                 memcpy(linear_timecode_raw_ready, linear_timecode_raw, sizeof(linear_timecode_raw) / 2);
  54.                 linear_timecode_ready = 1;
  55.             }
  56.         }
  57.     }
  58.     return 0;
  59. }
复制代码

3.  差分曼切斯特码解码

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

  3. static void move_right_linear_timecode_raw_7bits(unsigned char *raw, unsigned char nbytes, unsigned char nbits)
  4. {
  5.     unsigned char i;
  6.     unsigned char tmp;

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

  10.     for(i=0; i<nbytes - 1; i++) {
  11.         tmp = raw[i+1] & r_mask[nbits];
  12.         tmp <<= (8-nbits);
  13.         raw<span style="font-style: italic;"><span style="font-style: normal;"> >>= nbits;
  14.         raw</span><span style="font-style: normal;"> += tmp;
  15.     }
  16.     raw</span><span style="font-style: normal;"> >>= nbits;
  17. }

  18. static void move_left_linear_timecode_raw_7bits(unsigned char *raw, unsigned char nbytes, unsigned char nbits)
  19. {
  20.     unsigned char i;
  21.     unsigned char tmp;

  22.     if((nbits < 1) || (nbits > 7)) {
  23.         return;
  24.     }

  25.     for(i=0; i<nbytes - 1; i++) {
  26.         //prev_bit = raw</span><span style="font-style: normal;"> & 0x80;
  27.         tmp = raw[nbytes - i - 2] & l_mask[nbits];
  28.         raw[nbytes - i -1] <<= nbits;
  29.         tmp >>= (8-nbits);
  30.         raw[nbytes - i -1] += tmp;
  31.     }
  32.     raw[0] <<= nbits;
  33. }

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

  37.     x = nbits / 8;
  38.     y = nbits % 8;

  39.     if(x > 0) {
  40.         for (int i = 0; i < nbytes ; i++) {
  41.             raw</span><span style="font-style: normal;"> = raw[x+i];
  42.         }
  43.     }
  44.     move_right_linear_timecode_raw_7bits(raw, nbytes, y);
  45. }


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

  49.     x = nbits / 8;
  50.     y = nbits % 8;

  51.     if(x > 0) {
  52.         for (int i = 0; i < nbytes ; i++) {
  53.             raw[nbytes-i-1] = raw[nbytes-i-1-x];
  54.         }
  55.     }
  56.     move_left_linear_timecode_raw_7bits(raw, nbytes, y);
  57. }

  58. unsigned char get_bit_linear_timecode_raw(unsigned char index)
  59. {
  60.     unsigned char x = index/8;
  61.     unsigned char y = index%8;

  62.     if(linear_timecode_raw[x] & (1 <<y))
  63.         return 1;
  64.     else
  65.         return 0;
  66. }

  67. static void parse_differential_manchester_code(unsigned char *src,  unsigned char *dst, unsigned char dst_size)
  68. {
  69.     unsigned char i, j;
  70.     unsigned short tmp, tmp2;

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

  72.         tmp = (src[i*2 +1] << 8) + src[i*2];
  73.         dst</span><span style="font-style: normal;"> = 0;
  74.         for(j=0; j<8; j++) {
  75.             tmp2 = tmp & (3 << j*2);
  76.             tmp2 >>= j*2;
  77.             if((0 != tmp2) && (3 != tmp2)) {
  78.                 dst</span><span style="font-style: normal;"> |= (1<<j);
  79.             }
  80.         }
  81.     }
  82. }

  83. static char find_sync_code(unsigned char *src, unsigned char len, unsigned char *dst, unsigned char *valid_len)
  84. {
  85.     const unsigned short sync_code = 0xFCBF;
  86.     unsigned char i;
  87.     unsigned short tmp;
  88.     char ret=-1;

  89.     for (i=0; i<len-8; i++) {
  90.         tmp = (src[i+8] << 8) + src[i+9];
  91.         if (tmp == sync_code) {
  92.             ret =0;
  93.             *valid_len = len - i;
  94.             memcpy(dst, &src</span><span style="font-style: normal;">, 10);   //10Bytes equals 80bits
  95.             break;
  96.         }
  97.     }

  98.     return ret;

  99. }

  100. unsigned char ltc_dst_code[40][10]= {0};
  101. unsigned char ltc_dst_code_count = 0;
  102. unsigned char ltc_code_valid_len=0;
  103. unsigned char ltc_code[20] = {0};
  104. unsigned char raw_ready[60] = {0};
  105. unsigned short offset_bits = 0;
  106. unsigned short ltc_remain_bits = 0;
  107. unsigned char sec_ltc_code[20] = {0};
  108. unsigned char ltc_dst_code_cur[10]= {0};
  109. unsigned char new_frame =0;


  110. void parse_linear_timecode_raw()
  111. {
  112.     unsigned char tmp;
  113.     unsigned char raw_mv_right_bits = 0;

  114.     if(linear_timecode_status == LTC_STATUS_NEED_FIND_SYNC) {
  115.         isjam = 0;
  116.         memcpy(raw_ready, linear_timecode_raw_ready, sizeof(linear_timecode_raw_ready));
  117.         tmp = raw_ready[0] & 0x03;
  118.         while((0 != tmp) && (3 != tmp)) {
  119.             move_right_linear_timecode_raw_nbits(raw_ready, sizeof(raw_ready), 1);
  120.             raw_mv_right_bits ++;
  121.             tmp = raw_ready[0] & 0x03;
  122.         }

  123.         for (int i = 0; i < sizeof(linear_timecode_raw_ready)*8; ++i) {
  124.             memset(ltc_code, 0 , sizeof(ltc_code));
  125.             parse_differential_manchester_code(raw_ready,  ltc_code, sizeof(ltc_code));
  126.             //0xFCBF;
  127.             if((ltc_code[8] == 0xFC)&&(ltc_code[9]==0xBF)) {
  128.                 linear_timecode_status = !LTC_STATUS_NEED_FIND_SYNC;
  129.                 offset_bits = raw_mv_right_bits;
  130.                 break;
  131.             }
  132.             move_right_linear_timecode_raw_nbits(raw_ready, sizeof(raw_ready), 1);
  133.             raw_mv_right_bits ++;
  134.         }

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

  138.     } else {
  139.         isjam = 1;
  140.         memcpy(ltc_code, linear_timecode_raw_ready, sizeof(ltc_code));
  141.         parse_differential_manchester_code(ltc_code,  ltc_dst_code_cur, sizeof(ltc_dst_code_cur));
  142.         if((ltc_dst_code_cur[8] != 0xFC)||(ltc_dst_code_cur[9]!=0xBF)) {
  143.             linear_timecode_status = LTC_STATUS_NEED_FIND_SYNC;
  144.             LtcInput.tim_count = 0;     //reflesh tim2 period
  145.         } else {
  146.             new_frame =1;
  147.         }
  148.     }
  149. }
  150. </span></span>
复制代码


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

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

20201127114629167.png


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

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

20201127115308255.png


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

20201127115925296.png


解决办法,通修改 TIM中断处理程序,直接修改寄存器。 中间不停止,最终得到正确的波形
  1. void TIM3_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN TIM3_IRQn 0 */

  4.   /* USER CODE END TIM3_IRQn 0 */
  5.   HAL_GPIO_TogglePin(TEST1_GPIO_Port, TEST1_Pin);
  6.   htim3.Instance->SR = 0;
  7.   htim3.Instance->ARR = LtcInput.period;
  8.   htim3.Instance->CNT = 0;
  9.   ltc_input_timer_callback();

  10.   /* USER CODE END TIM3_IRQn 1 */
  11. }
复制代码


20201127120550172.png


收藏 评论0 发布时间:2021-11-14 23:04

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版