找回密码
 立即注册
查看: 100|回复: 9

IO 口 定时器 脉宽协议解码问题请教。

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:8
  • 最近打卡:2026-04-08 16:14:47
已绑定手机

3

主题

11

回帖

67

积分

注册会员

积分
67
发表于 2026-4-6 19:44:34 | 显示全部楼层 |阅读模式
这两天一直在调,没办法正确捕捉到脉冲宽度, STC32G8K48单片机, P3.7作为脉宽信号输入 (J1850_VPW),  起始信号实测为200us, 代码每次运行到 检测小于最小值163us报错返回。u16 j1850_vpw_recv_msg(uint8_t *msg_buf, 通过定时器0 1T模式下 运行(初值设为0)、停止来计时。 P37高阻输入。


u16 get_timer0(void)
{
        return  (((u16)(TH0)<<8 )|TL0);
}       

u16 j1850_vpw_recv_msg(uint8_t *msg_buf, u8 checkLength)
{
        uint8_t nbits;                        // 字节内的比特位置计数器
        uint8_t nbytes;                // 接收到的字节数
        uint8_t bit_state;// 用于比较比特状态,激活或被动
        uint16_t tcnt1_buf;
        /*
                等待响应
        */
// EA = 0;
        timer0_start();       
        while(0==VPW_IN)        // 只要总线是被动的(空闲)就运行      
        {
                if(get_timer0() >= WAIT_100us)        // 检查 100us
                {
                        TR0 = 0;
                        return J1850_RETURN_CODE_NO_DATA | 0x80;        // 错误,100us 内无响应
                }
        }
//           TR0        =        0;
        // 等待 SOF
        timer0_start();        // 重启 timer0
        while(1==VPW_IN)        // 只要总线是激活的(SOF 是一个激活符号)就运行
        {
                  if(get_timer0() >=  RX_SOF_MAX) {
                                TR0 = 0;
                        return J1850_RETURN_CODE_BUS_ERROR | 0x80
                                ;        // SOF 超时错误
                }
        }
//         TR0 = 0;
        if(get_timer0() < RX_SOF_MIN) {
                printf("TCNT = %u \r\n",get_timer0());
          TR0 = 0;
                return  J1850_RETURN_CODE_BUS_ERROR | 0x80;        // 错误,符号不是 SOF
        }
       
        bit_state = VPW_IN;        // 存储实际总线状态
        timer0_start();
        for(nbytes = 0; nbytes < checkLength ? 12 : RX_BUFFER_MAX_LEN; ++nbytes)
        {
                nbits = 8;
                do
                {
                        *msg_buf <<= 1;
                        while(VPW_IN == bit_state) // 比较上一个和实际总线状态,等待变化
                        {
                                if(TCNT1 >= RX_EOD_MIN        )        // 检查 EOD 符号
                                {
                                        TR0 = 0;
                                        return nbytes;        // 返回接收到的字节数
                                }
                        }
                        bit_state = VPW_IN;        // 存储实际总线状态
                  tcnt1_buf = TCNT1;
                        timer0_start();
                        if( tcnt1_buf < RX_SHORT_MIN) return J1850_RETURN_CODE_BUS_ERROR | 0x80;        // 错误,脉冲过短

                        // 检查短激活脉冲 = "1" 比特
                        if( (tcnt1_buf < RX_SHORT_MAX) && !VPW_IN )
                                *msg_buf |= 1;

                        // 检查长被动脉冲 = "1" 比特
                        if( (tcnt1_buf > RX_LONG_MIN) && (tcnt1_buf < RX_LONG_MAX) && VPW_IN )
                                *msg_buf |= 1;

                } while(--nbits);// 结束 8 比特 while 循环
               
                ++msg_buf;        // 存储下一个字节
               
        }        // 结束 12 字节 for 循环

        // 在最多 12 个字节后返回
        TR0 = 0;       
//        EA = 1;
        return nbytes;
}


回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:667
  • 最近打卡:2026-04-30 09:07:31

33

主题

2963

回帖

6704

积分

论坛元老

积分
6704
发表于 2026-4-7 08:57:33 | 显示全部楼层
从题目上来看,需要获取脉冲的时间,,,怎么看最好用的是 PWM的输出捕获功能。。。
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:8
  • 最近打卡:2026-04-08 16:14:47
已绑定手机

3

主题

11

回帖

67

积分

注册会员

积分
67
发表于 2026-4-7 09:32:29 | 显示全部楼层
_奶*** 发表于 2026-4-7 08:57
从题目上来看,需要获取脉冲的时间,,,怎么看最好用的是 PWM的输出捕获功能。。。 ...

额,那样我要换IO口了。 PWM能同时捕获高电平和低电平吗?感觉得用INT0中断。不过我感觉我这样直接启停定时器应该也是没问题的,不至于差那多,不知问题在哪。
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:708
  • 最近打卡:2026-04-30 11:14:46

9

主题

645

回帖

4566

积分

论坛元老

积分
4566
发表于 2026-4-7 10:01:16 | 显示全部楼层
  return  (((u16)(TH0)<<8 )|TL0);
这一句可能有问题
TH0是8位寄存器,不是变量,能不能使用(U16)强制转换成16位需要验证,建议采用临时变量处理这类操作
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:8
  • 最近打卡:2026-04-08 16:14:47
已绑定手机

3

主题

11

回帖

67

积分

注册会员

积分
67
发表于 2026-4-7 10:58:25 | 显示全部楼层
网*** 发表于 2026-4-7 10:01
return  (((u16)(TH0)

额,好的。 u16 get_timer0(void)
{
        u16 cnt,cnt1;
        do{
                        cnt = TH0;
                        cnt1 = TL0;
        }while(cnt==TH0);
       
        cnt =        (cnt<<8)|cnt1;
        return cnt;
}        不过问题还不是在这里。 这芯片定时器有没有16位可以直接读的。
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:667
  • 最近打卡:2026-04-30 09:07:31

33

主题

2963

回帖

6704

积分

论坛元老

积分
6704
发表于 2026-4-7 11:28:06 | 显示全部楼层
yan鈥*** 发表于 2026-4-7 09:32
额,那样我要换IO口了。 PWM能同时捕获高电平和低电平吗?感觉得用INT0中断。不过我感觉我这样直接启停定 ...

我不确定你用的这个芯片能不能一个脚同时检测高低电平,但是我用的STC8H8K64U 是可以的
截图202604071126539635.jpg

而且给出了参考例程,稍微改改就能用。


截图202604071127444698.jpg
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:428
  • 最近打卡:2026-04-30 11:07:34
已绑定手机

6

主题

364

回帖

1879

积分

金牌会员

积分
1879
发表于 2026-4-7 16:39:00 | 显示全部楼层
直接用pwm不行么
学习
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:8
  • 最近打卡:2026-04-08 16:14:47
已绑定手机

3

主题

11

回帖

67

积分

注册会员

积分
67
发表于 2026-4-8 16:14:47 | 显示全部楼层
patch*** 发表于 2026-4-7 16:39
直接用pwm不行么

我是想IO口,启停定时器测电容易实现
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:428
  • 最近打卡:2026-04-30 11:07:34
已绑定手机

6

主题

364

回帖

1879

积分

金牌会员

积分
1879
发表于 2026-4-9 10:24:18 | 显示全部楼层
yan鈥*** 发表于 2026-4-8 16:14
我是想IO口,启停定时器测电容易实现

哦,条条大路通罗马
学习
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:1
  • 最近打卡:2026-04-23 09:06:25

0

主题

1

回帖

4

积分

新手上路

积分
4
发表于 2026-4-23 09:06:25 | 显示全部楼层
你是做什么产品的,GM车系列的吗?能不能分享一下总线数据的,这个接收用PWM捕获最准确的,我用的就是PWM捕获,目前很准
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-5-1 10:29 , Processed in 0.143065 second(s), 105 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表