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

注册于 8年前

回答
47
文章
0
关注者
1

发布于2年前

开发板吃灰的重要原因,就是上班以后 时间围着工作内容转, 自己手上的开发板 没时间玩。
毕竟要玩开发板 一定要收拾桌子 摆上开发板 调试线材 打开电脑~~
等搞完这一套动作下来 接着就是要来一通 记忆恢复 复习上次学习内容

去年下半年 仅有的RTT学习时间,还是为了公司做一个小工具,现在开发完了,RTT又荒废了~~

发布于3年前

对于这个问题只能说 windows ? , 把用户习惯跟生态培养的太好了,而且软件API兼容性牛皮。

发布于3年前

既然是局域网就好办了,直接从电脑上获取PC端地址,
然后 单片机 向这个指定地址, 指定端口 进行通讯即可。

最简单的就是做一个UDP 向指定端口 定时广播。
然后,电脑端选择对应端口侦听 就可以看到有数据过来。

反过来也行,电脑端广播, ESP8266 侦听。

发布于3年前

咱俩名字拼音 有点像啊,D -> F ?

发布于3年前

image.png

你自己的截图里已经说明问题了, 这里 2800 里面少了 0x 十六进制开头吧。?
你在中断触发前,RT startup里面重新改写 SCB->VTOR ,这样等于是亡羊补牢

发布于3年前

跟着楼上两位又学到了新知识。
最近在研究bootloader 跟 向量重定向:
void SystemInit (void)里面有调用

  1. #ifdef VECT_TAB_SRAM
  2. SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
  3. #else
  4. SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
  5. #endif

也就是说,你在bootloader里面提前改写了 SCB->VTOR ,但是当引导进入APP之后,APP代码里面又把这个寄存器的值重新覆盖了。向量表被重新指向了bootloader FLASH区了。
如果你要是在bootloader 的中断处理里面做个打印的话,说不定还能有 消息输出。

发布于3年前

STM32 原厂出的IDE STM32CubeMX 不也挺好的吗?
学习入门啥的也够用了

另外,现在STM32 从2017年已经全部推HAL库了, 以前的CMSIS库 好像不流行了。
建议换新库,跟上时代

用RTT的studio 可以新建裸机工程,看图
HAL20211224172244.png

发布于3年前

主频1GHz 用LINUX 它不香吗? 自己找虐??
还是有极度性能压榨的需求?

发布于3年前

关闭全局中断试试? 循环结束时再打开中断。
看看差异

发布于3年前

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

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

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

发布于3年前

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

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

  1. static rt_uint32_t filter(rt_uint32_t ADC_DEV_CHANNEL) {
  2. rt_uint8_t i = 0, j = 0;
  3. rt_uint32_t value_buf[N];
  4. rt_uint32_t temp = 0,sum = 0;
  5. _ rt_adc_read(adc_dev, ADC_DEV_CHANNEL); //丢弃1
  6. rt_thread_delay(5); //延时
  7. rt_adc_read(adc_dev, ADC_DEV_CHANNEL); //丢弃2_
  8. for(i = 0; i < N; i++){
  9. _rt_thread_delay(5); //调整顺序_
  10. value_buf[i] = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
  11. }

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

发布于3年前

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

  1. 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。

发布于3年前

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

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

发布于3年前

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

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

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

发布于3年前

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

回到
顶部

发布
问题

投诉
建议