#2020征文-开发板#Wi-Fi IoT套件连PCF8563实现电子钟功能 原创 精华
首先跟同样新入手单片机开发的小伙伴分享一点I2C通信的知识。我估计大部分入手开发板的小伙伴都有一定程序开发的能力,但是底层开发可能是新接触,我看有的小伙伴配置开发环境都有障碍,其实并不是多复杂,只是首次接触很陌生罢了,大胆试,多搞几回就轻松应对了。
通信开发是单片机主要开发内容,通信方式和协议有很多种,针对应用场景和模块的情况选用合适的协议。各种协议大同小异,开始了解通透一种,理解其思想,其他协议也就很容易理解了。
如果是第一次看到这种图是不是有点懵。
大概过程就是:
1. 发送一段模块地址信息 + 读/写。
等待…
模块如果收到,会给你个回复 ACK
2. 你看到ACK响应,进行下一步
再发送一段,读/写寄存器地址信息。
模块收到,再给你回复ACK
3. 如果是写,就再发送写的内容信息。
如果是读,就接收模块发送来的返回信息。
换个现实场景理解一下,假设你喊你室友帮你取快递:
你:三胖子!(发送模块地址)
三胖子:干啥。(接听ACK)
你:给我取份快递。(发送寄存器地址)
三胖子:好的。(接听ACK)
你:接收室友给你送来的快递。(接收信息)
整个通信过程就是一问一答,双方不能同时问答,一方说话一方只能接听。当然具体过程还要复杂一些,比如接收信息也要给模块回复应答,但是主体过程就是这样的。这个过程大概了解一下就行,所有通信的细节部分都已经被鸿蒙下的函数封装好了,具体过程交由鸿蒙做就好,你只需要考虑要说什么做什么就行了。这个过程真的好简单。
看一下鸿蒙真对WifiIoT智能设备提供的I2C相关函数:
将数据写入I2C设备。
unsigned int I2cWrite(WifiIotI2cIdx id, unsigned short deviceAddr, const WifiIotI2cData *i2cData);
在i2c.h文件里有详细的说明,这里复制过来一一对照看一下每个参数的意义。
将数据写入I2C设备。
id表示I2C设备id。
deviceAddr表示I2C设备地址。
i2cData表示指向要写入的数据描述符的指针。
如果操作成功,返回WIFI_IOT_ SUCCESS;
否则返回在wifiiot_errno.h中定义的错误代码。
(百度翻译还是很准确的哦!哈)
从I2C设备读取数据。
unsigned int I2cRead(WifiIotI2cIdx id, unsigned short deviceAddr, const WifiIotI2cData *i2cData);
读取的数据将保存到i2cData指定的地址。
id表示I2C设备id。
deviceAddr表示I2C设备地址。
i2cData表示指向要读取的数据描述符的指针。
如果操作成功,返回WIFI_IOT_ SUCCESS;
否则返回在wifiiot_errno.h中定义的错误代码。
鸿蒙把I2C所使用的数据封装在一个结构体中。我们只需要把数据写入到这个结构体中,然后让函数自己处理就可以了。
typedef struct {
/** Pointer to the buffer storing data to send */
unsigned char *sendBuf;
/** Length of data to send */
unsigned int sendLen;
/** Pointer to the buffer for storing data to receive */
unsigned char *receiveBuf;
/** Length of data received */
unsigned int receiveLen;
} WifiIotI2cData;
定义I2C数据传输属性。
指向存储要发送的数据的缓冲区的指针
unsigned char *sendBuf;
要发送的数据长度
unsigned int sendLen;
指向用于存储要接收的数据的缓冲区的指针
unsigned char *receiveBuf;
接收数据的长度
unsigned int receiveLen;
具体用的时候,我们可以根据实际情况再封装一下。这是主要根据使用场景和模块所提供的功能。我针对我要使用PCF8563模块把I2C过程做了一点包装。可以看看我写的代码,也许能给你一点启发。参看我的代码。
在这次开发过程中还用到了GPIO管脚中断
很多老师都专门写了按键的中断触发,我也是仔细研读然后做了我这个程序的触发控制,老师的文章写的太详细了,实在没什么好再说明的,我在使用中也没有遇到什么问题,最多就是,要关闭看门狗功能,否者会重启,再就是当暂中断发的时候用到这个方法。
GpioSetIsrMask(WIFI_IOT_IO_NAME_GPIO_8, 0); 正常
GpioSetIsrMask(WIFI_IOT_IO_NAME_GPIO_8, 1); 暂停
ADC模数转换
用到OLED模块上的按键的时候碰到了ADC功能,这里先做个伏笔,主要是还没把鸿蒙下的ADC方法研究明白,而且数模转换应用场景非常多,以后用到专门的模块再仔细写写心得吧。暂时看老师们的代码照猫画虎也能运行,有时候会不稳定。
PCF8563是个比价常用的模块。
PCF8563 是PHILIPS 公司推出的一款工业级内含I2C 总线接口功能的具有极低功耗的多功能时钟/日历芯片。PCF8563 的多种报警功能、定时器功能、时钟输出功能以及中断输出功能能完成各种复杂的定时服务,甚至可为单片机提供看门狗功能。是一款性价比极高的时钟芯片,它已被广泛用于电表、水表、气表、电话、传真机、便携式仪器以及电池供电的仪器仪表等产品领域。
PCF8563并不是我们套件里所带的模块,只是赶巧我手上刚好有这么个模块。官方套件提供的模块有限,但是涵盖了单片开发的所有应用场景,如果每个模块都认真走一遍,那么基本解锁了鸿蒙单片机开发的所有知识了。在实际应用中,我们还是要使用各种功能的电子模块来实现更有趣的功能的。所以以后还是要更多尝试新模块的使用,也能提高鸿蒙系统的应用范围。
前面已经开发过AHT20温湿度模块,SSD1306模块,所以再开发PCF8563的过程就变的很简单。有很多内容都是重叠的,整体思路也是相通的,所以过程变得非常轻松。
任何一个模块上手第一步都是读它的技术手册,了解功能寄存器的配置。读手册的过程是枯燥的,只有坚持把手册读透,那么这个模块才算真正属于你。
我想要实现的功能是一个时钟功能,然后按需求和过程写一大坨流水账代码,测试走通,再把代码整理一下,最后归结为2部分,一部分设置时间,一部分读取时间。完了!
当你拥有了一个写时钟的能力,你就拥有了各种计时的能力,比如写个万年历,做个股票投资报时,等等。我通过一部电影获得灵感,做了一个到计数时钟,看时间飞快的流逝,会不会让看钟的人有压力感,治治拖延症呢。但结果除了无聊一点用没有。
PCF8563模块可以输出时钟信号,我开始设想通过Hi3861的1个端口接收时钟信模块发出的周期性低电平,把间隔设定为1秒,触发中断,然后读取模块的时间信息,发送到OLED上显示出来。这样就能每隔1秒显示一次。
OLED模块上有2个按键,想通过它们实现时间设置功能。这个两个按键很有趣,通过1个端口接收信号,通过测试信号的电压强度来区分是那个按键再工作。这时候需要通过ADC能来实现,(坑王艾希已经上线,哈开玩笑。)数模转换功能,难道不能通过2个端口来实现吗?当然不是,这可能是这套开发板设计的初衷,就是让你充分学习未来可能遇到的所有知识。闲话少叙,又解锁新姿势了。
通过2个按键实现功能控制:早期机械计算机用齿轮实现功能的切换,比如可编曲发音盒,有一种可编曲的,中间转子每个音节都可调,实现编曲功能,那种太高级了,没找到图片。我借鉴这种工作原理,来实现2个按键的复杂控制。
按键功能实现的原理就跟那个齿轮是一样的,S1驱动gear这个大齿轮,他有9齿,按一下,转1齿,循环往复,每一齿联动1个功能。S2驱动gears组的7个小齿轮,每个小齿轮针对1个时间的值。当然这不是唯一的控制方法,也可以做个大数组什么的,只是一种方法而已。
gear = 9 正常时间显示
gear = 0 进入设置状态
gear = 1 秒设置 gears[0]可以驱动
gear = 2 分设置 gears[1]可以驱动
gear = 3 时设置 gears[2]可以驱动
gear = 4 日设置 gears[3]可以驱动
gear = 5 周设置 gears[4]可以驱动
gear = 6 月设置 gears[5]可以驱动
gear = 7 年设置 gears[6]可以驱动
gear = 8 将设置好的值输入到时间模块
gear = 9 正常时间显示
因为不是套件中的模块,我只简单说一下主体程序工作结构。
1. 所有功能先初始化,准备好。
2. 做中断触发,每按1次驱动gear加1循环往复。
3. 建1个主循环,所有的工作就这个循环里了。
4. 针对gear的值,调用执行不同的功能。
完了! 谢谢。~哈
看代码吧,代码写的像流水账,我也懒了改了,欢迎纠错,有问题欢迎问。
随着代码越写越多,也深感C语言知识太少。我会再好好看看C教程,希望以后写的代码,能更好些。
比喻的挺详细的,下载代码来学习一波。
大宝贝大宝贝