客户发来一张原理图,一份传感器手册,一份需求文档,要求三天内完成软件开发,然后立马去现场调试不能出bug。
用的51单片机本身作为iic主机读传感器,然后还作为iic从机接受其他芯片控制,全部使用io模拟。
还好在3172的帮助下及时完成了任务,顺手把模拟iic的代码整理出来。
模拟主机部分是我几年前抄的老代码,一颗芯片可以用这套代码模拟多条iic总线。
很好用,所以我仿照主机的风格写了一套从机,当然也继承了这个特点。
主机需要实现1个延时函数和7个io操作函数,从机需要实现1个回调函数和5个io操作函数。
代码在这里:
https://gitee.com/ylc0919/mc3172/tree/master
模拟从机测试结果:在4M的线程下扫描io,最大可接受8K的scl频率
https://gitee.com/ylc0919/mc3172_mrs/
好久没更新了,最近拿到二代开发板,测试点了灯没啥问题。
依我这半年的使用来看,io口、串口、delay、锁、printf、模拟iic主这几个功能挺稳定。
锁要用到管理线程,对比一下当前线程分配,有没有配置管理线程,我代码里是用线程3
串口操作例程已上传:https://gitee.com/ylc0919/mc3172/tree/hal_uart/
串口部分大致如下:
延时函数更新说明:利用内核定时器做通用delay函数
### HAL 1.1.1 2022-08-18
1.优化delay_us()延时函数,略微提高us级延时的精度。
基于1.0.2帖子:https://whycan.com/t_8596.html
### HAL 1.0.2 2022-08-11
1.添加gpio输出输出方向修改函数。
### HAL 1.0.1 2022-08-06
1.修改头文件包含,现在使用hal库统一包含#include "mc31xx_hal.h"。
2.添加hal库通用定义及函数。
3.修复gpio不能正确读取的问题。
### HAL 1.0.0 2022-08-04
1.根据GPIO已知寄存器添加驱动库。
以hal库的形式来操作MC3172,由于该系列目前只有这一款mcu,算不上真正的hal库,不过好歹形似了~
项目地址在https://gitee.com/ylc0919/mc3172/,master分支是最新库文件以及实验代码,历史代码和稳定测试例程放在其他HAL开头的分支中。
所有库文件在Drivers目录下,可直接用这个目录替换官方MC3172.h文件。
使用hal库需包含#include "mc31xx_hal.h"
修改波特率后乱码的问题解决方法在此https://whycan.com/t_8606.html
群里的青菜大佬vegetableswim给出了一个更优的解决方案,在100us内延时比原版代码更优,2us延时误差减小超过10%,以下是两种代码
原版:
void delay_us(u32 nus)
{
u32 ticks;
u32 told, tnow, tcnt = 0;
GET_CORE_CNT(told); //读取内核定时器数值
ticks = nus * SYS_CORE_CLK_MHZ/4; //目标延时节拍数=需要延时时间(us)*CORE_CLK(MHz)/4
while (1)
{
GET_CORE_CNT(tnow);
if (tnow != told)
{
if (tnow < told)tcnt = 0xFFFFFFFF - told + tnow; //CORE_CNT递增32位,计算已延时节拍数
else tcnt = tnow - told;
if (tcnt >= ticks)break; //延时完成
}
};
}
优化版:
void delay_us(u32 nus)
{
u32 start,stop,ticks;
start=CORE_CNT;
ticks = nus * SYS_CORE_CLK_MHZ/4;
if(0xFFFFFFFF-start>=ticks){
stop=start+ticks;
while(CORE_CNT<stop && CORE_CNT>start){}
}
else{
stop=ticks-(0xFFFFFFFF-start);
while(CORE_CNT>start){}
while(CORE_CNT<stop){}
}
}
互斥锁测试通过,现在以上两个问题可以确认解决。详细见https://whycan.com/t_8639.html/
添加了基于官方开发板的测试程序,程序在仓库的hal_mux分支,master分支我会尝试一些奇奇怪怪的功能,不适合大家参考。
https://gitee.com/ylc0919/mc3172/tree/hal_mux/
工程基于梦程的cmake,用visual studio 和vs code打开均可,原开源地址在https://github.com/dreamcmi/MC3172-CMake.
MC3172使用全局变量做线程间通信,如何解决线程对全局资源的访问冲突问题是肯定绕不开的,自从上次给出了一种全局资源管理方法以来已经五天了,当时的两个问题属实有点把我难住了。
基于以上方法,我参照LiteOS的互斥锁做了一个MC3172的锁,刚好解决了之前遗留的两个问题,代码在此:https://gitee.com/ylc0919/mc3172/.
各种小bug困扰了我很久,刚刚测试通过,还没有来得及整理测试示例,有空我会做一个如GPIO一样的互斥锁demo分支,先来看看锁的效果:
互斥锁模块向外提供5个函数,其中常用的只有两个。
顺便提一下,现在本工程中的printf()函数已经可以安全的使用了。
简单修改,添加了基于官方开发板的测试程序,程序在仓库的hal_gpio分支,master分支我会尝试一些奇奇怪怪的功能,不适合大家参考。
https://gitee.com/ylc0919/mc3172/tree/hal_gpio/
hal_gpio分支代码基于梦程的cmake,用visual studio 和vs code打开均可,原开源地址在https://github.com/dreamcmi/MC3172-CMake.
方法是官方老哥讲的模型,我称之为申请者与审核者。一个线程审核所有全局资源,其他线程申请。
按照这个思路,我以论坛老哥提供的printf做实验,写了几行代码来操作测试。
直接上代码:
多线程printf串口打印测试通过,无乱码。
有两个问题:
1是如果第一个线程申请速度过快,其他所有线程都阻塞,一直是线程1在打印。
2是这样管理全局资源属实太麻烦了,每一个全局资源都需要新增三个变量和两个循环来管理。怎么样才能做成通用锁。
以前都是直接cv代码,没思考过这方面问题,一时半会还想不到办法。
今天下午200M晶振到手,焊上去重新分配了一下线程时钟,测了一下延时,果然舒服多了。
但是测串口的时候9600和921600乱码了,而115200和25600正常,咨询了官方老哥之后才知道两种乱码原因还不一样。
首先来看一下串口初始化代码。
引脚部分很简单,照着例子改就行,核心是三个频率:时钟分频、外设时钟、波特率。
外设时钟=系统时钟/时钟分频
我用的外部有源晶振做系统时钟200M,分频256,所以外设时钟=200000000/256=781250。
那么如何确定系统分频呢(敲黑板),我的串口乱码就是因为分频错了。官方说明是 外设时钟/波特率 的结果最好在100到200之间。
我的9600乱码是因为当时时钟分频选了64,外设时钟/波特率 超过了255,溢出了。
921600乱码是因为当时时钟分频也选了64,外设时钟/波特率 才3点多,不够。
芯片官方示例用的是mounriver studio,关于这个mrs用的怎么样呢,我简单说两句,至于我的身份,你明白就行,总而言之,这个事呢,现在就是这个情况,具体的呢,大家也都看得到,我因为这个身份上的问题,也得出来说那么几句,可能,你听的不是很明白,但是意思就是那么个意思,我的身份呢,不知道的你也不用去猜,这种事情见得多了,我只想说懂得都懂,不懂的我也不多解释...
不好意思拿错剧本了,咱回到正题,如果你用mounriver跑通了官方例程,又恰好装了vs2019及以上版本(我试了2019和2022没问题,其他不知道),那么就可以试试用vs来开发,否则本贴建议就看个乐。
示例工程放在了https://gitee.com/ylc0919/mc3172_vs.
逻辑大概就是在vs的框架里使用cmake和ninja来构建工程,cmake由梦程提供,开源地址在https://github.com/dreamcmi/MC3172-CMake.
使用效果是这样的:
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
GET_CORE_CNT(told); //读取内核定时器数值
ticks=nus*48; //目标延时节拍数=需要延时时间(us)*CORE_CLK(MHz)/4
while(1)
{
GET_CORE_CNT(tnow);
if(tnow!=told)
{
if(tnow<told)tcnt=0xFFFFFFFF-told+tnow; //CORE_CNT递增32位,计算已延时节拍数
else tcnt=tnow-told;
if(tcnt>=ticks)break; //延时完成
}
};
}