您的位置:首页 > 运维架构 > Shell

【Contiki学习】01.Contiki-stm32系统下实现serial-shell功能

2017-02-04 16:54 513 查看
一,背景介绍

之前通过网上收集资料(资料后期整理之后会在博客分享),在stm32上面跑通了,就是实现了简单的点灯程序,以及串口输出。

但是后期开发使用肯定需要用到shell,经过一番折腾后小有收获。

在这说一下开发环境:IAR+stm32vet6(ST官方库3.5+contiki3.0)

二,准备工作

1,在contiki源码中按照目录提取以下文件:







ps. stm32_shell.c是自行添加的代码

三,源码分析

1,先看一下main函数:

int main()
{
  dbg_setup_uart();
  led_init();
  printf("Initialising\r\n");
  
  clock_init();
  process_init();
  //shell serial_line 初始化
  uart1_set_input(serial_line_input_byte);
  serial_line_init();
  //
  process_start(&etimer_process, NULL);
  autostart_start(autostart_processes);
  printf("Processes running\r\n");
  while(1) {
    do 
    {
    } 
    while(process_run() > 0);
    idle_count++;
    /* Idle! */
    /* Stop processor clock */
    /* asm("wfi"::); */ 
  }
  return 0;
}


需要注意的是:

  //shell serial_line 初始化
  uart1_set_input(serial_line_input_byte);
  serial_line_init();
  //
2,usrt1_set_input定义在串口底层驱动里面

static int (* uart1_input_handler)(unsigned char c);

void uart1_set_input(int (* input)(unsigned char c))
{
    uart1_input_handler = input;
}
先建立一个函数指针:

static int (* uart1_input_handler)(unsigned char c);再通过
uart1_set_input(serial_line_input_byte);
将(*uart1_input_handler)指向 serial_line_input_byte()函数,

这样就可以通过调用uart1_input_handler();将串口接到的数据导入serial_line中,从而可以通过serial_line_process进程进行命令分析做出相应处理。

uart1_input_handler();的调用写在串口中断中即可:

void USART1_IRQHandler(void)
{
ENERGEST_ON(ENERGEST_TYPE_IRQ);
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
if(uart1_input_handler != NULL)
{
 		/* Read one byte from the receive data register */
uint8_t buf = USART_ReceiveData(USART1);
uart1_input_handler(buf);
}
    }
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
}


3,通过上面的处理已经把串口接收到的数据导入serial_line中了,当然串口配置初始化在这就不用多说了,

接下来就是要把shell进程加入系统了:

调用serial_shell_init()函数即可

定义:

void
serial_shell_init(void)
{
process_start(&serial_shell_process, NULL);
}
就是开启serial_shell_process进程,但是我这边新建立一个进程,用于后续其他自定义的shell命令的初始化:

#include "contiki.h"
#include "shell.h"
#include "serial-shell.h"

PROCESS(stm32_shell_process, "STM32 Contiki Shell");

PROCESS_THREAD(stm32_shell_process, ev, data)
{
PROCESS_BEGIN();

serial_shell_init();//初始化shell

PROCESS_END();
}
然后再将改进程加入main函数即可,

到这边就已经完成了shell的功能,可以通过串口看见



发送 help(加回车)



这是一些默认的命令,你也可以自己定义一些命令,通过阅读shell部分的源码进一步了解原理。

4,在shell.c中可以看见关于上面打印出来的命令的定义,其实每个shell命令对应一个process,

PROCESS(help_command_process, "help");
SHELL_COMMAND(help_command, "help", "help: shows this help",
&help_command_process);
SHELL_COMMAND(question_command, "?", "?: shows this help",
&help_command_process);
PROCESS(shell_killall_process, "killall");
SHELL_COMMAND(killall_command, "killall", "killall: stop all running commands",
&shell_killall_process);
PROCESS(shell_kill_process, "kill");
SHELL_COMMAND(kill_command, "kill", "kill <command>: stop a specific command",
&shell_kill_process);
PROCESS(shell_null_process, "null");
SHELL_COMMAND(null_command, "null", "null: discard input",
&shell_null_process);
PROCESS(shell_exit_process, "exit");
SHELL_COMMAND(exit_command, "exit", "exit: exit shell",
&shell_exit_process);
SHELL_COMMAND(quit_command, "quit", "quit: exit shell",
&shell_exit_process);
PROCESS_THREAD(shell_kill_process, ev, data)
{
  struct shell_command *c;
  char *name;
  PROCESS_BEGIN();

  name = data;
  if(name == NULL || strlen(name) == 0) {
    shell_output_str(&kill_command,
    "kill <command>: command name must be given", "");
  }

  for(c = list_head(commands);
      c != NULL;
      c = c->next) {
    if(strcmp(name, c->command) == 0 &&
       c != &kill_command &&
       process_is_running(c->process)) {
      command_kill(c);
      PROCESS_EXIT();
    }
  }

  shell_output_str(&kill_command, "Command not found: ", name);
  
  PROCESS_END();
}


5,添加自定义命令通过一下方式即可:

#include "contiki.h"
#include "shell.h"

#include "stdio.h"
#include "string.h"
#include "stm32f10x.h"

PROCESS(shell_blink_process, "shell blink");
SHELL_COMMAND(blink_command, "blink",
"blink on/off : led on/off", &shell_blink_process);

static void
led_init()
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);

GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7;
GPIO_Init(GPIOF, &GPIO_InitStructure);
}

/**
* \brief
* \param
*
*/
static void
led_on()
{
GPIO_SetBits(GPIOF, GPIO_Pin_7);
}

static void
led_off()
{
GPIO_ResetBits(GPIOF, GPIO_Pin_7);
}

PROCESS_THREAD(shell_blink_process, ev, data)
{
PROCESS_BEGIN();
if(data != NULL)
{
if(strcmp(data, "on"))
{
led_on();
}
else if(strcmp(data, "off"))
{
led_off();
}
else
{
printf("Invalid param!\n");
}
}

PROCESS_END();
}

void
shell_blink_init(void)
{
led_init();
shell_register_command(&blink_command);
}

a,通过SHELL_COMMAND(blink_command, "blink",

              "blink on/off : led on/off", &shell_blink_process);定义shell命令;

b,通过shell_register_command(&blink_command);在shell初始化的时候一并初始化即可

其他的内容,在后续的学习中将陆续记录。

ps.我还只是个初级入门的菜鸟,有些地方写的有问题也请大家指点啊。

贴上我的源码:(仅供参考)

点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐