fubaojun2006
fubaojun2006
哇(挖)~~坑~~~啊!

注册于 5 years ago

回答
21
文章
0
关注者
0

你的帖子,发布于 2021-11-28 03:00:25
我摸了摸我的头发。

看了你两篇关于ADC DMA的帖子了,也看了你参考的源连接。
我决定 还是按裸机方式 初始化ADC ,然后初始化DMA 。用一个任务去处理DMA搬运过来的数据。

这样感觉还简单点---来自一个没有学设备管理框架的渣渣

看你的程序,一次打开 读取8次,然后做了排序,后取 中位值平均滤波法 已经很完美了。
我觉得可以试试把 NTC 通道 安排在几个不同的PORT 的IO口上,
比如A口一个NTC , C口 一个NTC ,排除这种外部硬件引起的串扰问题。

或者是在filter函数做一下调整,先读取两次丢弃,然后先延时,然后再读取。

static rt_uint32_t filter(rt_uint32_t ADC_DEV_CHANNEL) {
    rt_uint8_t i = 0, j = 0;
    rt_uint32_t value_buf[N];
    rt_uint32_t temp = 0,sum = 0;

_        rt_adc_read(adc_dev, ADC_DEV_CHANNEL); //丢弃1
        rt_thread_delay(5); //延时
        rt_adc_read(adc_dev, ADC_DEV_CHANNEL); //丢弃2_
    for(i = 0; i < N; i++){
        _rt_thread_delay(5); //调整顺序_
        value_buf[i] = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
    }

你写的程序代码,实在是挑不出毛病的。
再不然就是 像你这样对时间不敏感的,就降低ADC CLK频率,加大采样时间周期数。
再一个就是 在硬件引脚那里加入一个小的滤波电容。

我读了源码,代码的调用路径:

rt_adc_read  --》 dev->ops->convert(dev, channel, &value);  --》 stm_adc_ops.convert = stm32_get_adc_value   --》 ADC_ChanConf.Channel =  stm32_adc_get_channel(channel); ADC_ChanConf.Rank = 1;  --》 HAL_ADC_ConfigChannel  --》 HAL_ADC_GetValue

可以确认的是,这个rt_adc_read 确定读取的是你设定的通道5的电压值。stm32_get_adc_value这个函数的作用就是只配置Rank = 1这样一个regular group, 另外,ADC1_CONFIG.Init.NbrOfConversion = 1, 也就是每次只转换这一个通道。 所以可以确认的是 读取的是硬件通道5 PA5 ADC12_IN5的值。

那为什么你读取的值是对的呢,这个要从硬件IO 上找原因了。
ADC-IO-20211202105615.png

从IO结构图上看出,模拟输入 与 数字输入 是一条线上的。只是数字输入这里多了一个TTL 施密特触发器。
当芯片复位时,IO口的模式为 数字浮空输入,一般来说浮空输入模式 对外的漏电流为1uA 这很小的。 所以,对于模拟输入那里 几乎不产生电压影响。 所以,就算硬件ADC去获取PA5的电压,也依然能够反映外部真实的ADC值。

那么根据这硬件图,我推测,如果是把PA5 设定为PP输出模式 ,ADC 依然可以读到IO上的电压值。只是这个值会随着PA5的输出电压变化而变化。 这就是为什么读外部ADC时要设定为模拟输入的原因: 切断其他电路对外部模拟电压的干扰。

如果想要测试我说的这个,可以用一个滑动变阻器,抽头 放在PA5这里。
两种情况:

  • 1.不对PA5 初始化, 滑动变阻器 看ADC值。
  • 2.对PA5 初始化PP输出,定时1s 翻转电平,看ADC值。

好像空口无凭 啊 (ಥ_ಥ) 我去实验一下。不过通道不一定选择你这个PA5。

这种优化问题,大概率需要自己动手丰衣足食。
官方人手不够,社区又不会针对性的优化一些问题。
去git上提PR吧,这样也许有些用。

除了这个UART ,还有 drv_gpio 中断也有一些不合理, 上次我提了一下,后面大家的态度就是自己动手解决。

对于这一个us级延时函数,我觉得有几个地方要进行细节分析一下。不开新帖子了姑且就在这个帖子发一下吧。

void rt_hw_us_delay(rt_uint32_t us)
{
    rt_uint32_t start, now, delta, reload, us_tick, total_delay_ticks;
    start = SysTick->VAL;
    reload = SysTick->LOAD;
    us_tick = SystemCoreClock / 1000000UL; //这里取一个us所需的硬件计时数量
    //为了优化代码的运行,我觉得应该把后面的us_tick * us 放到这里来进行一次运行即可。不必要while判断时每次都执行乘法,加快CPU运算速度。
    //那么,以STM32 72MHz,系统SysTick设定为1ms中断为例,reload = SysTick->LOAD = 72000;
    //us_tick = SystemCoreClock / 1000000UL = 72;
    //那么,1ms以内的总延时时间,总计数 是 小于72*1000;
    //假设一个极端例子,RTT用上了10GHz的CPU,那么,reload = SysTick->LOAD = 10000000;
    //us_tick = 10,000,000,000 / 1000000UL = 10,000;
    //那么,1ms以内的总延时时间,总计数 是 小于10,000*1000;
    //对应于rt_uint32_t 来说是不会溢出的,total_delay_ticks 定义为uint32_t 足够用了。
    total_delay_ticks = us_tick * us;
    do {
        now = SysTick->VAL;
        delta = start > now ? start - now : reload + start - now;//对于这里有一个重点问题
        //这里start > now ? 是通过利用SysTick计数器的递减计数来判定,是否发生了一次定时器溢出
        //举STM32例说明一下:
        //例子1: start = 70000;total_delay_ticks = 50000(约694.4us);
        //那么,当now = SysTick->VAL= 19999,即可满足条件,delta = start > now ? start - now 
        //例子2: start = 70000;total_delay_ticks = 80000(约1111.1us);
        //那么,无论计数器怎么计数,都不能满足条件;当刚溢出时,start < now =reload + start - now 总数<reload 1ms; 当溢出超过1ms时,又会出现start > now =start - now 总数计算明显出现了错位; 
        //所以,为了保险起见,这个usdelay的调用最好不要超过一次中断的周期时长,即total_delay_ticks<(reload = SysTick->LOAD)
    } while(delta < total_delay_ticks);
}

或者,这个函数在开始做一个判断,如果输入的us数 > 系统的中断时长,则进行强制设定不允许超过;以保证系统不会卡死在这里。当然,这样也可能会让调试者误认为程序没有bug。也可以用一个内核panic oops警告用户?

任何的方便与简单,背后都是有人做好了基础工作而来。
LINUX内核一个简单的make就可以生成一个几MB的zImage 可是背后的Makefile 可是经历了几十年的修修改改维护。
随着软件规模越来越大,产品越来越复杂,往后嵌入式产品就只有两头了,一头在芯片原厂维护SDK代码,一头在终端用户养活螺丝钉工程师各司其职。
个人学习者,学习曲线更加陡峭。

我想没有人会明确要求消除警告,至少我还没遇到这样的行业。
但是自己要对代码中出现的警告了解清楚,知道这些警告究竟有没有 风险。
如果是有风险的警告,最好是消除。避免隐患。
例如: printf 打印时,经常会出现 字符串 char * 与 const char * 这类 警告,这种属于调试打印的,对程序功能无影响,则可以忽略。

如果是程序 代码赋值类的,有强制或隐式类型转换的则需要小心一些。
还有一类就是if 判断条件, 有时候 == 会 少打一个等号,变成了赋值。这个会导致逻辑错误的。所以有些编程规范会要求常量放在条件的左边 if(0 == a) 这样写,如果漏了一个等号 也无所谓 if(0 = a) 会报错。
如果是 if(a = 0) 则可想而知,编译器足够智能还好。

咱俩名字拼音快差不多了,我就来先回你一下。
你这个发送越来越快? 这个现象没法理解,你得具体说一说你程序的目的意图。
另外,DMA 的基本功能跟中断用途,还是需要靠芯片手册了解清楚的。
虽然RTT作为操作系统托管了很多硬件功能,还加入了操作系统的便利特性功能。
但遇到问题的时候,还是需要自己硬啃问题,甚至于修改底层的驱动代码来符合自己的目的意图。

上次我就遇到串口的问题,后来还是通过修改底层驱动逻辑,实现自己的功能。
这个也是RTT团队提倡的。毕竟,他们也没精力把全部驱动都做的那么细化,只能说跑DEMO OK ,剩下的靠自己发展。

程序里用到的变量,自己再重新初始化一遍。
不知道是不是因为变量值不对引起的,程序流程逻辑问题。

为啥不考虑修改你下位机上报的VID PID ??

修改后问题解决:

case CDC_SET_CONTROL_LINE_STATE:
        data->connected = RT_TRUE; //解决回显需要DTR问题 (setup->wValue & 0x01) > 0?RT_TRUE:RT_FALSE;
        RT_DEBUG_LOG(RT_DEBUG_USB, ("vcom state:%d \n", data->connected));
        dcd_ep0_send_status(func->device->dcd);
        break;

解决DTR问题-2021-5-18.png

确实,DTR 需要打开,这边我也遇到了

我现在也遇到这个问题,用《友善串口助手》打开,就不行,不能接受下位机发来的数据,用putty打开一次之后OK,然后这个时候保持板子不动,关闭PUTTY,再次使用《友善串口助手》打开,就好了,能够正常接收了。

回到
顶部

发布
问题

投诉
建议