uEnergy安装完毕后,会在安装目录下看到apps文件夹,里面有很多的例子,从这一节开始我将会挑选部分例子进行讲解,掌握这些例子后,会对CSR uEnergy的开发有一个大致的了解。
今天我们以示例代码中的PIO为例,讲解PIO的一些用法。
首先,打开SDK的安装目录,找到PIO文件夹:
打开后,双击pio.xiw打开:
打开后会有以下界面:
左侧为Workspace,我们点击C Files,打开main.c文件:
打开后,我们会看到main.c文件的内容,这里重点讲几个函数:
1. AppPowerOnReset
2. AppInit
3. AppProcessSystemEvent
4. AppProcessLmEvent
首先来讲解AppPowerOnReset函数,在pio的例子中,此函数为空:
其实多数的应用中,此函数都为空。看官方的解释,此函数只有在reset或者Hibernate or Dormant sleep状态醒来才会被调用,而我们多数的应用中,将此函数留空即可。
AppInit函数:
此函数比较重要,整个程序起来后会进入此函数,用户可以在此函数中添加一些初始化函数,此函数只被调用一次,且不能在此函数中添加死循环,否则系统会崩溃。
AppProcessSystemEvent函数:
此函数是系统事件的入口,系统事件有4种sys_event_wakeup、sys_event_battery_low、sys_event_pio_changed、sys_event_pio_ctrlr:
Sys_event_wakeup:芯片通过wakeup引脚起来会产生此事件;
Sys_event_battery_low:电池电量低会触发此事件;
Sys_event_pio_changed:io口状态改变会触发;
Sys_event_pio_ctrlr:pio controller产生的中断会引起此事件。
最后一个函数AppProcessLmEvent:
此函数在pio的例子中也是空,因为此函数处理了一些蓝牙事件,此例子只是对PIO口操作,没有涉及到蓝牙,所以,此函数也必然为空,关于蓝牙事件,会在以后的章节中说明。
看完这些,相信你会明白哪里才是我们看代码的切入点了吧,自然是AppInit函数,这里为了看起来方便,我将解释放在了代码中:
void AppInit(sleep_state last_sleep_state)
{
//首先这里初始化两个LED口
//设置PIO_LED0和PIO_LED1口为pio_mode_user
PioSetModes((1UL << PIO_LED0) | (1UL << PIO_LED1), pio_mode_user);
//设置PIO_LED0口为输出
PioSetDir(PIO_LED0, PIO_DIR_OUTPUT);
//设置PIO_LED1口为输出
PioSetDir(PIO_LED1, PIO_DIR_OUTPUT);
//设置PIO_LED0和LED1为强上拉
PioSetPullModes((1UL << PIO_LED0) | (1UL << PIO_LED1),
pio_mode_strong_pull_up);
//接下去设置了一个按钮
//设置BUTTON为pio_mode_user
PioSetMode(PIO_BUTTON, pio_mode_user);
//设置BUTTON口为输入
PioSetDir(PIO_BUTTON, PIO_DIR_INPUT);
//设置BUTTON口为弱上拉
PioSetPullModes((1UL << PIO_BUTTON), pio_mode_weak_pull_up);
//设置上升沿和下降沿都触发Sys_event_pio_changed事件
PioSetEventMask((1UL << PIO_BUTTON), pio_event_mode_both);
restartLedSeq();
}
PIO口的操作基本上是在appinit函数中设置PIO口的模式,普通IO口为pio_mode_user,然后设置PIO口为输入或者输出,然后配置上拉下拉或者浮空,如果为输入,还可以配置是否触发Sys_event_pio_changed事件。
在初始化函数的最后,调用restartLedSeq函数并结束整个初始化:
restartLedSeq函数内,我们看到一个PioSets函数,从注释很容易理解是将LED0和LED1设置为0,即关闭LED。
这里,就告诉我们设置IO口状态可以用PioSets函数,关于此函数的具体说明,可以查看API说明。
接下来我们看按键被按下后程序做了哪些处理:
void AppProcessSystemEvent(sys_event_id id, void *data)
{
//这里为sys_ event_pio_changed事件的入口
if (id == sys_event_pio_changed)
{
const pio_changed_data *pPioData = (const pio_changed_data *)data;
//判断是不是按键导致sys_event_pio_changed事件
if (pPioData->pio_cause & (1UL << PIO_BUTTON))
{
bool validStateChange = FALSE;
//判断当前是否为高,如果是高,则表明刚刚发生的事件是由低到高,即上升沿触发,表示按键是被松开的
if (pPioData->pio_state & (1UL << PIO_BUTTON))
{
g_cur_button_state = button_state_up;
}
//相反,如果不是高,则表明按键是被按下
else
{
if (g_cur_button_state == button_state_up)
{
validStateChange = TRUE;
}
g_cur_button_state = button_state_down;
}
//如果一个完整的按键发生,则切换LED闪烁状态
if (validStateChange)
{
goToNextLedSeq();
}
}
}
}
关于goToNextLedSeq()函数,其中也没有新的PIO口操作知识点,这里就不做过多的解释了,读者可以自己去研究一下每一个LED状态是怎么样的。
好了,关于PIO口操作的解释就说明到这里,另外IO口不仅仅只有输入输出两种功能,还有UART功能,IIC功能,SPI功能等等,会在后续章节中逐一讲解。