本文旨在剖析main函数,从更高层次理解Contiki系统。先是给出源码,接着总结功能,最后深入源码分析。
1. main函数源码
//filename:contiki-main.c
#include <stm32f10x.h>
#include <stm32f10x_dma.h>
#include <stdint.h>
#include <stdio.h>
#include <debug-uart.h>
#include <sys/process.h>
#include <sys/procinit.h>
#include <etimer.h>
#include <sys/autostart.h>
#include <clock.h>
int main()
{
dbg_setup_uart(); //串口初始化,与硬件相关(注1)
usart_puts("Initialising\n"); //向串口打印字符串"Initialising"
clock_init();//时钟初始化,与硬件相关,见3.3
process_init(); //进程初始化,详情见3.1
process_start(&etimer_process, NULL); //启动etimer_process,详情见3.2
autostart_start(autostart_processes); //启动指针数组autostart_processes[]里的所有进程,详情见3.2
while (1)
{
/*执行完所有needspoll为1的进程及处理完所有队列,详情见3.2*/
do
{
}
while (process_run() > 0);
}
return 0;
}
注:串口初始化和时钟初始化与硬件相关(我用的MCU是STM32F103RBT6),不深入讨论,主要基于以下两个原因:其一,这部分对理解系统影响不大;其二,我对硬件不是很熟。
2. 程序解读
系统先进行一系列初始化(串口、时钟、进程),接着启动系统进程etimer_process
和指针数组autostart_processes[]
里的所有进程,到这里就启动了所有的系统进程(当然,后续的操作还可能动态产生新进程)。接下来的工作,就是系统反复处理所有needspoll
标记为1
的进程及事件队列中所有事件。而处理事件过程中(典型情况是让某些进程继续执行)又可能产生新的事件,再处理事件,系统如此反复运行。
3. 源码详解
3.1 进程初始化
/****进程初始化****/
void process_init(void)
{
/*初始化事件队列*/
lastevent = PROCESS_EVENT_MAX;
nevents = fevent = 0;
#if PROCESS_CONF_STATS
process_maxevents = 0;
#endif
process_current = process_list = NULL; //初始化进程链表
}
3.2 注明
- 有关etimer_process参考博文《系统进程etimer_process 》
- 有关process_start参考博文《启动一个进程process_start》
- 有关process_run参考博文《深入理解process_run函数》
autostart_start
函数用于启动autostart_processes
指针数组里的进程,源代码如下:
//autostart_start(autostart_processes);
void autostart_start(struct process *const processes[])
{
int i;
for(i = 0; processes[i] != NULL; ++i)
{
process_start(processes[i], NULL);
PRINTF("autostart_start: starting process '%s'\n", processes[i]->name);
}
}
autostart_processes
由宏AUTOSTART_PROCESSES
定义,详情参见博文《实例hello_world剖析》第三部分。其源代码如下:
#define AUTOSTART_PROCESSES(...) \
struct process * const autostart_processes[] = {__VA_ARGS__, NULL}
3.3 时钟初始化
clock_init
用于配置系统产生嘀嗒的间隔,即每隔72000000/CLOCK_SECOND
产生一次系统嘀嗒(72000000是指1s可以产生最大的嘀嗒数),也就是说1秒钟可以产生CLOCK_SECOND
次时钟中断。
void clock_init()
{
SysTick_Config(72000000 / CLOCK_SECOND);
}
/*CLOCK_SECOND宏定义*/
#define CLOCK_CONF_SECOND 10
#ifdef CLOCK_CONF_SECOND
#define CLOCK_SECOND CLOCK_CONF_SECOND
#else
#define CLOCK_SECOND (clock_time_t)32
#endif
SysTick_Config
函数展开如下,与硬件相关(我用的MCU是STM32F103RBT6):
/**
* @brief Initialize and start the SysTick counter and its interrupt.
*
* @param ticks number of ticks between two interrupts
* @return 1 = failed, 0 = successful
*
* Initialise the system tick timer and its interrupt and start the
* system tick timer / counter in free running mode to generate
* periodical interrupts.
*/
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}