shell学习一:shell命令行实现

1:以s5pv210芯片的开发板为例。标准输入输出设置为串口的输入输出,通过开发板串口连接PC主机,使用SecureCRT软件,来构建一个类似uboot中的shell命令行界面;

2:shell命令行界面的实质就是提供人机交互,类似GUI、xwindows等;

shell命令行界面的实现原理:

利用一个while死循环构建一个命令行终端,这个命令行终端可以读取、解析命令、并介串口来输出,把结果在SecureCRT中打印出来;

需要如下几个函数:start.S 用来做基本的初始化:如关开门狗、电源置锁、初始化时钟、初始化DDR等;

接下来初始化串口,构建一个以串口输入输出的标准化函数;

下面这段代码初始化了串口,并且构建了以串口为输入、输出的函数putc、getc

#define GPA1CON     0xE0200020
#define ULCON2        0xE2900800
#define UBRDIV2        0xE2900828
#define UDIVSLOT2    0xE290082C
#define    UCON2        0xE2900804
#define    UFCON2        0xE2900808
#define    UMCON2        0xE290080C
#define UTXH2        0xE2900820
#define UTRSTAT2    0xE2900810
#define URXH2        0xE2900824

#define rGPA1CON    (*(unsigned int*)0xE0200020)
#define rULCON2        (*(unsigned int*)0xE2900800)
#define rUBRDIV2    (*(unsigned int*)0xE2900828)
#define rUDIVSLOT2    (*(unsigned int*)0xE290082C)
#define rUCON2        (*(unsigned int*)0xE2900804)
#define rUFCON2        (*(unsigned int*)0xE2900808)
#define rUMCON2        (*(unsigned int*)0xE290080C) 
#define rUTXH2        (*(unsigned int*)0xE2900820) 
#define rUTRSTAT2    (*(unsigned int*)0xE2900810)
#define rURXH2        (*(unsigned int*)0xE2900824)
 
void uart_init(void)
{
    //设置线接口为Rx Tx 模式       GPA1CON, R/W, Address = 0xE020_0020    
    rGPA1CON &= ~(0xFF);
    rGPA1CON |= 0x22;    
    //设置ULCON                  8字节 无奇偶校验 终止位为1位 无起始 ULCON2, R/W, Address = 0xE290_0800
    rULCON2 = 0x3;
    //设置UCON                    UCON2, R/W, Address = 0xE290_0804, R/W, Address = 0xE290_0804
    rUCON2 = 0x5;
    //设置UFCON    无FIFO            UFCON2, R/W, Address = 0xE290_0808
    rUFCON2 = 0x0;
    //设置UMCON    无流控            UMCON2, R/W, Address = 0xE290_080C
    rUMCON2 = 0x0;
    //设置波特率   UBRDIV2, R/W, Address = 0xE290_0828   UDIVSLOT2, R/W, Address = 0xE290_082C
    rUBRDIV2 = 0x23;
    rUDIVSLOT2 = 0x0808;
        
}
#if 0
#define GPA0CON        0xE0200000
#define UCON0         0xE2900004
#define ULCON0         0xE2900000
#define UMCON0         0xE290000C
#define UFCON0         0xE2900008
#define UBRDIV0     0xE2900028
#define UDIVSLOT0    0xE290002C
#define UTRSTAT0    0xE2900010
#define UTXH0        0xE2900020    
#define URXH0        0xE2900024    

#define rGPA0CON    (*(volatile unsigned int *)GPA0CON)
#define rUCON0        (*(volatile unsigned int *)UCON0)
#define rULCON0        (*(volatile unsigned int *)ULCON0)
#define rUMCON0        (*(volatile unsigned int *)UMCON0)
#define rUFCON0        (*(volatile unsigned int *)UFCON0)
#define rUBRDIV0    (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0    (*(volatile unsigned int *)UDIVSLOT0)
#define rUTRSTAT0    (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0        (*(volatile unsigned int *)UTXH0)
#define rURXH0        (*(volatile unsigned int *)URXH0)

// 串口初始化程序
void uart_init(void)
{
    // 初始化Tx Rx对应的GPIO引脚
    rGPA0CON &= ~(0xff<<0);            // 把寄存器的bit0~7全部清零
    rGPA0CON |= 0x00000022;            // 0b0010, Rx Tx
    
    // 几个关键寄存器的设置
    rULCON0 = 0x3;
    rUCON0 = 0x5;
    rUMCON0 = 0;
    rUFCON0 = 0;
    
    // 波特率设置    DIV_VAL = (PCLK / (bps x 16))-1
    // PCLK_PSYS用66MHz算        余数0.8
    //rUBRDIV0 = 34;    
    //rUDIVSLOT0 = 0xdfdd;
    
    // PCLK_PSYS用66.7MHz算        余数0.18
    // DIV_VAL = (66700000/(115200*16)-1) = 35.18
    rUBRDIV0 = 35;
    // (rUDIVSLOT中的1的个数)/16=上一步计算的余数=0.18
    // (rUDIVSLOT中的1的个数 = 16*0.18= 2.88 = 3
    rUDIVSLOT0 = 0x0888;        // 3个1,查官方推荐表得到这个数字
}
#endif
void putc(char ch)
{
    //直接写入 UTX2就可以然后自动发送 UTXH2, W, Address = 0xE290_0820
    //以轮询的方式发送检查是否已经发送完成        UTRSTAT2, R, Address = 0xE290_0810
    
    if (ch == '
') {
        while (!(rUTRSTAT2 & (0x1<<1)));
        rUTXH2 = (unsigned int)('
');
    }
    while (!(rUTRSTAT2 & (0x1<<1)));
    rUTXH2 = (unsigned int)ch;
    
}


char getc(void)
{
    //        URXH2, R, Address = 0xE290_0824
    while (!(rUTRSTAT2 & (1<<0)));
    return (rURXH2 & 0xFF);
}

第二部构建两个函数puts打印字符串、gets读取字符串、

void puts(const char *pch)
{
    while ((*pch)!='') {
        putc(*pch);
        pch++;
    }
}

char *gets(char *pbuf)
{
    char *p = pbuf;
    
    while ((*pbuf = getc()) != '
') {        //window中用键盘输入的回撤为/r/n
                                            //所以判断是否输入回撤时要判断是否为/r        
        if (*pbuf != '') {            
            putc(*pbuf);            
            *pbuf++;
        }
        else {
            if(pbuf > p) {
                putc('');                        //这段代码是用来实现回显
                putc(' ');                        //如果是的话putc ,然后在输入空格把原来的字符删除
                putc('');                        //在输出会原位。            
                pbuf--;    
            }
                    
        }
        
    }
    *pbuf = '';    
    putc('
');
    return p;
    
}


void* memset(void *buf, int c, int n)
{
    int i = 0;
    char *p = (char*)buf; 
    
    while (i < n) {
        *p = (char)c;
        i++;
        p++;
    }
    return buf;    
}

 

#include "stdio.h"

int main(void)
{
    char buf[100];
    //初始化时钟
    clock_init();    
    
    //初始化uart        
    uart_init();
    puts("x210_shell:
");
    while (1) {
        puts("210x_bhc#");
        memset(buf, 0, sizeof(buf));        
        gets(buf);
        puts("210x_bhc#what you put is ");
        puts(buf);    
        puts("
");
        
        
    }    
    return 0;
}

 这样就实现了一个简单的命令行回显功能,之后再加入命令。。下章继续。

原文地址:https://www.cnblogs.com/biaohc/p/6308938.html