什么是Shell
Shell是壳的意思,计算机中Shell常用于表示一种命令行的用户操作接口,Shell常用来表示封装,由于计算机很复杂,所以常把功能的实现和调用分开,Shell里边是功能实现,外边是功能调用,所以Shell可以看做是复杂功能实现的封装并向外部提供的比较容易的而接口
程序或者操作系统的接口
程序或者操作系统在运行起来之后,都会为用户提供操作界面,该界面就是一种Shell,用户通过该Shell来调用操作系统内部的实现功能,Shell编程就指的是在Shell的层次上进行编程,基于Shell编程相对于语言编程比较容易一些,例如Win中的bat批处理或者Linux的脚本编程
GUI和CMD的Shell
GUI图形用户界面的Shell,用户体验比较友好,操作比较简单,易学易用,适合使用程序或者操作系统来工作的人,CMD相对比较麻烦,譬如Linux的终端或者Win中的CMD命令行界面,使用起来有点门槛,但是可以进行方便的Shell编程,适合做开发的人员
Shell运行原理
命令行的Shell运行原理,实际上是一个死循环,其中包含三部分,分别是命令接收,解析,执行串联的循环,命令行有标准的命令集,用户操作时必须知道操作需要通过哪个命令来实现,如果随便输入的命令不是标准命令集中的一个,则会提示用户命令不合法,让用户重新输入,用户输入命令的界面是命令行界面,需用户输入一行命令才能生效,常见的uboot就是一个裸机Shell,Linux终端和Win的CMD就是一个命令行Shell,Win,ubuntu以及Android的图形界面就是图形界面的Shell
Shell编程
先写一个简单的PC上的Shell小程序
简单的Shell程序模仿
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LEN 256
#define MAX_CMD_LEN 3
// 定义标准命令
#define led "led"
#define lcd "lcd"
#define pwm "pwm"
// 最多支持命令数
char cmdset[MAX_CMD_LEN][MAX_LINE_LEN];
// 初始化命令集函数
void init_cmd_set(void) {
memset(cmdset,0,sizeof(cmdset));
strcpy(cmdset[0],led);
strcpy(cmdset[1],lcd);
strcpy(cmdset[2],pwm);
}
int main(void) {
// 初始化命令集
init_cmd_set();
// 开启死循环
while(1) {
// 先打印命令行提示符
printf("Welcome:");
// 存放用户的输入内容
char str[MAX_LINE_LEN];
// 清空数组
memset(str,0,sizeof(str));
// 获取用户输入
scanf("%s",str);
// 解析用户输入的命令
int i;
// 遍历命令集
for(i = 0;i < MAX_CMD_LEN;i++) {
// 查看是否是命令集中的命令
if(!strcmp(str,cmdset[i])) {
// 找到了命令,需要执行
printf("%s\n",str);
printf("%s\n","processing cmd...");
//执行完退出
break;
}
}
// 没找到对应的命令
if(i >= MAX_CMD_LEN) {
// 提示用户没有该命令
printf("%s is a valid command,please input the correct commamd!\n",str);
}
}
return 0;
}
移植ShellDemo到开发板
我们把原来写的uart的例子和上节课写的demo结合在一起,可以得到一个开发板上运行的ShellDemo:
#include "stdio.h"
#include "uart.h"
void memset(char *p,int val,int length) {
int i;
for(i = 0;i < length; i++) {
p[i] = val;
}
}
int main(void) {
char buf[100] = {0};
uart_init();
puts("shell:\n");
while(1) {
puts("someone#");
memset(buf,0,sizeof(buf));
gets(buf);
puts("您输入的是: ");
puts(buf);
puts("\n");
}
return 0;
}
定义命令集
把Demo中定义的命令移植过来,可以实现一个命令的程序:
#include "cmd.h"
#include "stdio.h"
#include "string.h"
#define MAX_LINE_LEN 256
#define MAX_CMD_LEN 3
// 定义标准命令
#define led "led"
#define lcd "lcd"
#define pwm "pwm"
// 最多支持命令数
char cmdset[MAX_CMD_LEN][MAX_LINE_LEN];
// 初始化命令集函数
void init_cmd_set(void) {
memset((char *)cmdset,0,sizeof(cmdset));
strcpy(cmdset[0],led);
strcpy(cmdset[1],lcd);
strcpy(cmdset[2],pwm);
}
// 解析命令
int cmd_parser(char *cmd) {
// 解析用户输入的命令
int i;
// 遍历命令集
for(i = 0;i < MAX_CMD_LEN;i++) {
// 查看是否是命令集中的命令
if(!strcmp(cmd,cmdset[i])) {
// 找到了命令,需要执行
puts(cmd);
puts("processing cmd...");
//执行完退出
break;
}
}
// 没找到对应的命令
if(i >= MAX_CMD_LEN) {
// 提示用户没有该命令
puts("not a valid command,please input the correct commamd!\n");
}
return 0;
}
//执行命令
void cmd_exec(void) {
}
然后在main函数中就可以调用这些函数来分析和处理命令:
#include "stdio.h"
#include "uart.h"
#include "cmd.h"
#include "string.h"
int main(void) {
char buf[100] = {0};
init_cmd_set();
uart_init();
puts("shell:\n");
while(1) {
puts("someone#");
memset(buf,0,sizeof(buf));
gets(buf);
// 解析命令
cmd_parser(buf);
// 执行命令
cmd_exec();
}
return 0;
}
添加命令
我们最开始添加了三个命令,led,lcd和pwm,但是都不是真是的命令,并没有实际的执行,我们需要把这些命令真实的运行起来,最终我们的命令代码如下所示:
#include "cmd.h"
#include "stdio.h"
#include "string.h"
#include "led.h"
#include "pwm.h"
#include "lcd.h"
#include "adc.h"
#define MAX_LINE_LEN 256
#define MAX_CMD_LEN 4
#define CMD_ARGS 2
#define CMD_ARGS_LEN 20
// 定义标准命令
#define led "led"
#define lcd "lcd"
#define pwm "pwm"
#define adc "adc"
// 最多支持命令数
char cmdset[MAX_CMD_LEN][MAX_LINE_LEN];
char acmd[CMD_ARGS][CMD_ARGS_LEN];
int cmd_index = -1;
// 初始化命令集函数
void init_cmd_set(void) {
memset((char *)cmdset,0,sizeof(cmdset));
memset((char *)acmd,0,sizeof(acmd));
strcpy(cmdset[0],led);
strcpy(cmdset[1],lcd);
strcpy(cmdset[2],pwm);
strcpy(cmdset[3],adc);
}
// 解析命令
int cmd_parser(char *cmd) {
// 解析用户输入的命令
cmd_split(acmd,cmd);
int i;
cmd_index = -1;
// 遍历命令集
for(i = 0;i < MAX_CMD_LEN;i++) {
// 查看是否是命令集中的命令
if(!strcmp(acmd[0],cmdset[i])) {
// 找到了命令,需要执行
cmd_index = i;
break;
}
}
return 0;
}
void handle_led() {
led_init();
if (!strcmp(acmd[1],"on")) {
led_on();
} else if (!strcmp(acmd[1],"off")) {
led_off();
} else {
puts("use 'led on' or 'led off' to switch the led mode!\n");
}
}
void handle_lcd() {
lcd_init();
if (!strcmp(acmd[1],"draw")) {
draw_ascii_ok(500,306,GREEN,"Hello");
} else {
puts("use 'lcd draw' to draw some words!\n");
}
}
void handle_adc() {
adc_init();
if (!strcmp(acmd[1],"collect")) {
adc_collect();
} else {
puts("use 'adc collect' to switch the adc mode!\n");
}
}
void handle_pwm() {
timer2_pwm_init();
if (!strcmp(acmd[1],"on")) {
timer2_pwm_start();
} else if (!strcmp(acmd[1],"off")) {
timer2_pwm_stop();
} else {
puts("use 'pwm on' or 'pwm off' to switch the pwm mode!\n");
}
}
//执行命令
void cmd_exec(void) {
switch (cmd_index) {
case 0:
// 处理led
handle_led();
break;
case 1:
// 处理lcd
handle_lcd();
break;
case 2:
// 处理pwm
handle_pwm();
break;
case 3:
// 处理adc
handle_adc();
break;
default:
puts("not a valid command,please input the correct commamd!\n");
break;
}
}
如果要详细操作这些硬件,或者增加控制命令,可以根据实现代码增添即可。