本帖最后由 dvd1478 于 2016-1-10 21:34 编辑
1、前言
Contiki是一款小型开源,易于移植的多任务操作系统,专门为无线传感网设计,适合内存受限制的网络系统。
由于Contiki需要适应多种平台 ,所以一般的驱动分为抽像接口和具体实现两部分。
上一篇分析了Contiki的移植过程
[EVAL-WSN]操作系统篇——Contiki移植分析https://www.cirmall.com/bbs/forum.php?mod=viewthread&tid=46002&fromuid=23447
这里做个实例有个感观认识
2、代码分析
以最简单的led驱动为例:
Contiki的led驱动可简单分为抽象接口和具体实现两部分
LED 属于外设备,抽像接口一般在 contiki-2.5\core\dev\目录下,具体实现contiki-2.5\cpu\目录下(一般以-arch结尾)
2.2)抽像接口
leds.h
- /**
- * \defgroup leds LEDs API
- *
- * The LEDs API defines a set of functions for accessing LEDs for
- * Contiki plaforms with LEDs.
- *
- * A platform with LED support must implement this API.
- * @{
- */
-
- #ifndef __LEDS_H__
- #define __LEDS_H__
-
- void leds_init(void);
-
- /**
- * Blink all LEDs.
- */
- void leds_blink(void);
-
- /*ledv 进行位设置 有且仅有以下四种可能
- 0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80
- unsigned char leds_arch_get(void)
- 等等,定义了 unsigned char = 8bit
- 当修改即可以
- */
- #ifndef LEDS_GREEN
- #define LEDS_GREEN 1
- #endif /* LEDS_GREEN */
- #ifndef LEDS_YELLOW
- #define LEDS_YELLOW 2
- #endif /* LEDS_YELLOW */
- #ifndef LEDS_RED
- #define LEDS_RED 4
- #endif /* LEDS_RED */
- #ifndef LEDS_BLUE
- #define LEDS_BLUE LEDS_YELLOW
- #endif /* LEDS_BLUE */
-
- #ifdef LEDS_CONF_ALL
- #define LEDS_ALL LEDS_CONF_ALL
- #else /* LEDS_CONF_ALL */
- #define LEDS_ALL 7
- #endif /* LEDS_CONF_ALL */
-
- /**
- * Returns the current status of all leds (respects invert)
- */
- unsigned char leds_get(void);
- void leds_on(unsigned char leds);
- void leds_off(unsigned char leds);
- void leds_toggle(unsigned char leds);
- void leds_invert(unsigned char leds);
-
- /**
- * Leds implementation 具体实现
- */
- void leds_arch_init(void);
- unsigned char leds_arch_get(void);
- void leds_arch_set(unsigned char leds);
-
- #endif /* __LEDS_H__ */
复制代码 leds.c- #include "dev/leds.h"
- #include "sys/clock.h"
- #include "sys/energest.h"
-
- static unsigned char leds, invert;
- /*---------------------------------------------------------------------------*/
- static void
- show_leds(unsigned char changed)
- {
- if(changed & LEDS_GREEN) {
- /* Green did change */
- if((invert ^ leds) & LEDS_GREEN) {
- ENERGEST_ON(ENERGEST_TYPE_LED_GREEN);//方便跟踪节能设计了energest模块
- } else {
- ENERGEST_OFF(ENERGEST_TYPE_LED_GREEN);
- }
- }
- if(changed & LEDS_YELLOW) {
- if((invert ^ leds) & LEDS_YELLOW) {
- ENERGEST_ON(ENERGEST_TYPE_LED_YELLOW);
- } else {
- ENERGEST_OFF(ENERGEST_TYPE_LED_YELLOW);
- }
- }
- if(changed & LEDS_RED) {
- if((invert ^ leds) & LEDS_RED) {
- ENERGEST_ON(ENERGEST_TYPE_LED_RED);
- } else {
- ENERGEST_OFF(ENERGEST_TYPE_LED_RED);
- }
- }
- leds_arch_set(leds ^ invert);
- }
- /*---------------------------------------------------------------------------*/
- void
- leds_init(void)
- {
- leds_arch_init();
- leds = invert = 0;
- }
- /*---------------------------------------------------------------------------*/
- void
- leds_blink(void)
- {
- /* Blink all leds. */
- unsigned char inv;
- inv = ~(leds ^ invert);
- leds_invert(inv);
-
- clock_delay(400);
-
- leds_invert(inv);
- }
- /*---------------------------------------------------------------------------*/
- unsigned char
- leds_get(void) {
- return leds_arch_get();
- }
- /*---------------------------------------------------------------------------*/
- void
- leds_on(unsigned char ledv)
- {
- unsigned char changed;
- changed = (~leds) & ledv;
- leds |= ledv;
- show_leds(changed);
- }
- /*---------------------------------------------------------------------------*/
- void
- leds_off(unsigned char ledv)
- {
- unsigned char changed;
- changed = leds & ledv;
- leds &= ~ledv;
- show_leds(changed);
- }
- /*---------------------------------------------------------------------------*/
- void
- leds_toggle(unsigned char ledv)
- {
- leds_invert(ledv);
- }
- /*---------------------------------------------------------------------------*/
- /* invert the invert register using the leds parameter */
- void
- leds_invert(unsigned char ledv) {
- invert = invert ^ ledv;
- show_leds(ledv);
- }
- /*---------------------------------------------------------------------------*/
复制代码 在面对用户层时只调用
void leds_init(void);
void leds_blink(void);
unsigned char leds_get(void); void leds_on(unsigned char leds); void leds_off(unsigned char leds); void leds_toggle(unsigned char leds); void leds_invert(unsigned char leds);
这么多函数公点在于调用show_leds函数 除屏蔽硬件层的影响外,还有一个更重要的意义就是进行跟踪节能统计与优化(energest模块的功能)
2.2)具体实现部分
contiki-2.5\cpu\arm\aducrf101\leds-arch.c
contiki提供了控制LED的三大接口,分别是:
void leds_arch_init(void) LED初始化函数
unsigned char leds_arch_get(void) LED状态获取函数
void leds_arch_set(unsigned char leds) LED状态设置函数
各LED状态按位排列,例如最低位为LED1的状态,最低位为1则LED点亮,最低位为0则LED熄灭。以此类推。
- #include "contiki-conf.h"
- #include "dev/leds.h"
- #include "device.h"
- #include "gpio.h"
-
-
- #define LED_ARCH_RED GPIO_LED_RED //P1.2
- #define LED_ARCH_GREEN GPIO_LED_GREEN //P4.2
- #define LED_ARCH_BLUE GPIO_LED_BLUE //P4.0
-
- void leds_arch_init(void)
- {
- //pADI_GP4->GPCON |= GP4CON_CON0_GPIO | GP4CON_CON1_GPIO | GP4CON_CON2_GPIO | GP4CON_CON3_GPIO;
- //pADI_GP4->GPOEN |= GP4OEN_OEN0_OUT | GP4OEN_OEN1_OUT | GP4OEN_OEN2_OUT | GP4OEN_OEN3_OUT;
- //pADI_GP4->GPSET |= GP4SET_SET0_SET | GP4SET_SET1_SET | GP4SET_SET2_SET | GP4SET_SET3_SET;
- pADI_GP4->GPCON |= GP4CON_CON0_GPIO | GP4CON_CON2_GPIO ;
- pADI_GP4->GPOEN |= GP4OEN_OEN0_OUT | GP4OEN_OEN2_OUT ;
- pADI_GP4->GPSET |= GP4SET_SET0_SET | GP4SET_SET2_SET ;
-
- // For RED LED on BUNCH Rev-A
- pADI_GP1->GPCON |= GP1CON_CON2_GPIO;
- pADI_GP1->GPOEN |= GP1OEN_OEN2_OUT;
- pADI_GP1->GPCLR |= GP1CLR_CLR2_CLR;
- }
-
- unsigned char leds_arch_get(void)
- {
-
- return ((pADI_GP1->GPOUT & GP1OUT_OUT2) ? 0 : LEDS_RED)
- | ((pADI_GP4->GPOUT & GP4OUT_OUT2) ? 0 : LEDS_GREEN)
- | ((pADI_GP4->GPOUT &GP1OUT_OUT0) ? 0 : LEDS_BLUE);
-
- }
-
- void leds_arch_set(unsigned char leds)
- {
- if(leds & LEDS_RED) { pADI_GP1->GPCLR |= GP1CLR_CLR2; } else { pADI_GP1->GPSET |= GP1SET_SET2_SET; }
- if(leds & LEDS_GREEN) { pADI_GP4->GPCLR |= GP4CLR_CLR2; } else { pADI_GP4->GPSET |= GP4SET_SET2_SET; }
- if(leds & LEDS_BLUE) { pADI_GP4->GPCLR |= GP4CLR_CLR0; } else { pADI_GP4->GPSET |= GP4SET_SET0_SET; }
- }#include "contiki-conf.h"
- #include "dev/leds.h"
- #include "device.h"
- #include "gpio.h"
-
-
- #define LED_ARCH_RED GPIO_LED_RED //P1.2
- #define LED_ARCH_GREEN GPIO_LED_GREEN //P4.2
- #define LED_ARCH_BLUE GPIO_LED_BLUE //P4.0
-
- void leds_arch_init(void)
- {
- //pADI_GP4->GPCON |= GP4CON_CON0_GPIO | GP4CON_CON1_GPIO | GP4CON_CON2_GPIO | GP4CON_CON3_GPIO;
- //pADI_GP4->GPOEN |= GP4OEN_OEN0_OUT | GP4OEN_OEN1_OUT | GP4OEN_OEN2_OUT | GP4OEN_OEN3_OUT;
- //pADI_GP4->GPSET |= GP4SET_SET0_SET | GP4SET_SET1_SET | GP4SET_SET2_SET | GP4SET_SET3_SET;
- pADI_GP4->GPCON |= GP4CON_CON0_GPIO | GP4CON_CON2_GPIO ;
- pADI_GP4->GPOEN |= GP4OEN_OEN0_OUT | GP4OEN_OEN2_OUT ;
- pADI_GP4->GPSET |= GP4SET_SET0_SET | GP4SET_SET2_SET ;
-
- // For RED LED on BUNCH Rev-A
- pADI_GP1->GPCON |= GP1CON_CON2_GPIO;
- pADI_GP1->GPOEN |= GP1OEN_OEN2_OUT;
- pADI_GP1->GPCLR |= GP1CLR_CLR2_CLR;
- }
-
- unsigned char leds_arch_get(void)
- {
-
- return ((pADI_GP1->GPOUT & GP1OUT_OUT2) ? 0 : LEDS_RED)
- | ((pADI_GP4->GPOUT & GP4OUT_OUT2) ? 0 : LEDS_GREEN)
- | ((pADI_GP4->GPOUT &GP1OUT_OUT0) ? 0 : LEDS_BLUE);
-
- }
-
- void leds_arch_set(unsigned char leds)
- {
- if(leds & LEDS_RED) { pADI_GP1->GPCLR |= GP1CLR_CLR2; } else { pADI_GP1->GPSET |= GP1SET_SET2_SET; }
- if(leds & LEDS_GREEN) { pADI_GP4->GPCLR |= GP4CLR_CLR2; } else { pADI_GP4->GPSET |= GP4SET_SET2_SET; }
- if(leds & LEDS_BLUE) { pADI_GP4->GPCLR |= GP4CLR_CLR0; } else { pADI_GP4->GPSET |= GP4SET_SET0_SET; }
- }
复制代码
2.3) leds应用函数
- #include "contiki.h"
- #include "dev/leds.h"
- /*---------------------------------------------------------------------------*/
- PROCESS(test_etimer_process, "Test ET");
- AUTOSTART_PROCESSES(&test_etimer_process);
- /*---------------------------------------------------------------------------*/
- PROCESS_THREAD(test_etimer_process, ev, data)
- {
- static struct etimer et;
- PROCESS_BEGIN();
- while(1) {
- etimer_set(&et, CLOCK_SECOND); // etimer溢出周期为1s
- PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
- leds_on(LEDS_GREEN); // 打开LEDS_GREEN
- etimer_set(&et, CLOCK_SECOND);
- PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
- leds_off(LEDS_GREEN);
- }
-
- PROCESS_END();
- }
- /*---------------------------------------------------------------------------*/
复制代码 2.4)最简单的main函数
- int main(void)
- {
- init_hw();/*硬件初始化 与 Contiki无关*/
- /*外设设备初始化*/
- leds_init();
- /* Clock */
- clock_init();
- /* Initialize process subsystem */
- process_init();
- /* etimers must be started before ctimer_init */
- process_start(&etimer_process, NULL);//设置etimer_process 进程
- ctimer_init();//设置ctimer_process 进程
-
- /* 默认程序 */
- autostart_start(autostart_processes);
- while(1) {
- process_run();
- }
- }
复制代码 3、总结
这时看到闪灯的效果,有人做个闪灯有没有必要做得这么复杂,做闪灯并不是重要的目的,重要的目的是为也了解Contiki的运行机制,了解Contiki的外设的开发流程
|