ARM裸板开发——简单编写实现“shell”功能

简介: ARM裸板开发——简单编写实现“shell”功能

文章目录

简单编写实现一个裸板环境下使用的“shell”功能程序,可以控制LED、beep等。

main主程序设计

主要函数:strcmp实现

LED初始化及控制功能实现

UART初始化及控制功能实现

使用Makefile编译

执行结果


简单编写实现一个裸板环境下使用的“shell”功能程序,可以控制LED、beep等。

main主程序设计
#include "uart.h"
#include "strcmp.h"
#include "led.h"
//保存从上位机接收的数据信息
static char buf[32];
void main(void)
{
    //1.初始化UART
    uart_init();
    //2.初始化LED
    led_init();
    //3.根据用户需求完成业务
    while(1) {
        uart_puts("\n Shell#");
        uart_gets(buf, 32);
        if(!my_strcmp(buf, "led on"))
            led_on();
        else if(!my_strcmp(buf, "led off"))
            led_off();
        else
            uart_puts("\n Your command is invalid\n");
    }
}


主要函数:strcmp实现

实现strcmp字符串比较函数,用于对比用户命令的输入。


  • strcmp.h
#ifndef __STRCMP_H
#define __STRCMP_H
/*功能:比较字符串函数声明
 *返回值:
    str1=str2:返回0
    str1>str2:返回大于0
    str1<str2:返回小于0
  参数:
    str1:要比较的字符串
    str2:要比较的字符串
 * */
extern int my_strcmp(const char *str1,
                     const char *str2);
#endif


  • strcmp.c
#include “strcmp.h”
/*str1 = "hello", str2 = "hfllo"*/
int my_strcmp(const char *str1, 
                const char *str2)
{
    while(*str1) {
        if(*str1 != *str2)
            return *str1 - *str2;
        str1++;
        str2++;
    }
    return *str1 - *str2;
}


LED初始化及控制功能实现

  • led.h
#ifndef __LED_H
#define __LED_H
/*声明寄存器的基地址信息*/
#define GPIOCOUT (*(volatile unsigned long *)0xC001C000)
#define GPIOCOUTENB (*(volatile unsigned long *)0xC001C004)
#define GPIOCALTFN0 (*(volatile unsigned long *)0xC001C020)
/*声明操作函数*/
extern void led_init(void);
extern void led_on(void);
extern void led_off(void);
#endif


  • led.c
#include "led.h"
//初始化函数定义
void led_init(void)
{
    //1.配置引脚功能为GPIO功能
    GPIOCALTFN0 &= ~(3 << 24);
    GPIOCALTFN0 |= (1 << 24);
    //2.配置引脚为输出功能
    GPIOCOUTENB |= (1 << 12);
}
//开灯函数定义
void led_on(void)
{
    //1.配置输出寄存器为0
    GPIOCOUT &= ~(1 << 12);
}
//关灯函数定义
void led_off(void)
{
    //1.配置输出寄存器为1
    GPIOCOUT |= (1 << 12);
}


UART初始化及控制功能实现

  • uart.h
#ifndef __UART_H
#define __UART_H
/*UART相关寄存器定义*/
#define ULCON0 (*(volatile unsigned long *)0xC00A1000)
#define UCON0 (*(volatile unsigned long *)0xC00A1004)
#define UTRSTAT0 (*(volatile unsigned long *)0xC00A1010)
#define UTXH0 (*(volatile unsigned long *)0xC00A1020)
#define URXH0 (*(volatile unsigned long *)0xC00A1024)
#define UBRDIV0 (*(volatile unsigned long *)0xC00A1028)
#define UFRACVAL0 (*(volatile unsigned long *)0xC00A102C)
#define GPIODALTFN0 (*(volatile unsigned long *)0xC001D020)
#define GPIODALTFN1 (*(volatile unsigned long *)0xC001D024)
#define UARTCLKENB (*(volatile unsigned long *)0xC00A9000)
#define UARTCLKGENOL (*(volatile unsigned long *)0xC00A9004)
/*UART操作函数声明*/
//初始化函数
extern void uart_init(void);
//发送字符函数
extern void uart_putc(char c);
//发送字符串函数
extern void uart_puts(char *str);
//接收字符函数
extern char uart_getc(void);
//接收字符串函数
extern void uart_gets(char buf[], int len);
#endif


  • uart.c
#include "uart.h"
//初始化函数的定义
void uart_init(void)
{
    //1.配置RX和TX对应的引脚功能分别为UARTRXD0和UARTTXD0功能
    //GPIOD14配置UARTRXD0
    //GPIODALTFN0[29:28]=01
    GPIODALTFN0 &= ~(3 << 28);
    GPIODALTFN0 |= (1 << 28);
    //GPIOD18配置UARTTXD0
    //GPIODALTFN1[5:4]=01
    GPIODALTFN1 &= ~(3 << 4);
    GPIODALTFN1 |= (1 << 4);
    //2.配置UART的时钟为50MHZ
    //此时钟给波特率产生器使用
    //PLL[0]=800MHZ
    //n=800MHZ/50MHZ=16
    //n=CLKDIV0+1=>CLKDIV0=15
    //CLKDIV0=UARTCLKGENOL[12:5]
    UARTCLKGENOL &= ~(0xFF << 5);
    UARTCLKGENOL |= (0xF << 5);
    //3.配置UART的波特率为115200
    //数据位为8
    //不采用奇偶校验
    //停止为为1位
    ULCON0 = 3;
    UCON0 = 5;
    UBRDIV0 = 26; 
    UFRACVAL0=2;
    //4.打开UART的时钟
    UARTCLKENB |= (1 << 2);
}
//发送字符函数定义
//以软件形式将数据放到发送缓冲区
//发送移位器自动将数据一位一位的
//发送到TX数据线,速度就是115200
void uart_putc(char c)
{
    //1.由于CPU把数据放到缓存区的速度要远远快于发送移位器把数据放到TX数据线上的速度,CPU再发送下一个字符的时候应该判断一下发送缓冲区是否为空,如果为空,可以发,否则继续死等待
    while(!(UTRSTAT0 & 0x2));
    //2.将数据放到发送缓冲区
    UTXH0 = c;
    //3.发送回车字符
    if(c == '\n')
        uart_putc('\r');
}
//发送字符串函数定义
//str = "helloworld\n"
void uart_puts(char *str)
{
    while(*str) {
        uart_putc(*str);
        str++;
    }
}
//获取字符函数定义
char uart_getc(void)
{
    //1.由于CPU读取UART接收缓冲区数据的速度
    //要远远快于接收移位器从RX数据线获取数据的数据,所以CPU在读取数据的时候,首先要判断
    //接收移位器的速度由波特率产生器决定
    //接收缓冲区是否为空
    //如果为空:CPU在原地死等
    //如果不为空:CPU就可以读取数据
    while(!(UTRSTAT0 & 0x1));
    //2.从接收缓冲区寄存器读取数据
    return (URXH0 & 0xFF);
}
//获取字符串函数定义
//调用:char buf[32];uart_gets(buf, 32)
void uart_gets(char buf[], int len)
{
    int i;
    for (i = 0; i < len - 1; i++) {
        //保存上位机发送的字符
        buf[i] = uart_getc();
        //上位机回显
        uart_putc(buf[i]);
        //判断输入期间是否有回车操作
        //如果有,跳出循环
        if(buf[i] == '\r')
            break;
    }
    buf[i] = 0; //最后添加结束符
}


使用Makefile编译

  • Makefile
#定义变量
NAME=shell
BIN=$(NAME).bin
ELF=$(NAME).elf 
OBJ=main.o uart.o led.o strcmp.o
CROSS_COMPILE=arm-cortex_a9-linux-gnueabi-
CC=$(CROSS_COMPILE)gcc
LD=$(CROSS_COMPILE)ld
OBJCOPY=$(CROSS_COMPILE)objcopy
CP=cp
RM=rm
INSTALLPATH=/tftpboot
  #链接选项
LDFLAGS=-nostdlib -nostartfiles -Ttext=0x48000000 -emain
  #编译选项
CFLAGS=-nostdlib
#定义编译规则
shell.bin:shell.elf
  arm-cortex_a9-linux-gnueabi-objcopy -O binary shell.elf shell.bin
$(BIN):$(ELF)
  $(OBJCOPY) -O binary $(ELF) $(BIN)
  $(CP) $(BIN) $(INSTALLPATH)
#
#     #shell.elf:main.o uart.o led.o strcmp.o
#     arm...ld -nostartfiles -nostdlib -... -o shell.elf main.o ...
$(ELF):$(OBJ)
  $(LD) $(LDFLAGS) -o $(ELF) $(OBJ)
#各种.o:各种.c
#  各种编译
%.o:%.c
  $(CC) $(CFLAGS) -c -o $@ $<
#    
#    #伪目标
#当执行make clean时,仅仅执行clean伪目标对应的命令
clean:
  $(RM) $(BIN) $(ELF) $(OBJ)


执行结果

在板子上uboot界面执行:

tftp 48000000 shell.bin
go 48000000


相关文章
|
6月前
|
算法 编译器 Linux
【Qt4 部署】ARM系统上使用Qt 4 进行开发的QWS 等环境变量部署
【Qt4 部署】ARM系统上使用Qt 4 进行开发的QWS 等环境变量部署
120 0
|
6月前
|
存储 监控 Shell
【Shell 命令集合 磁盘管理 】Linux 关闭磁盘配额功能 quotaoff命令使用教程
【Shell 命令集合 磁盘管理 】Linux 关闭磁盘配额功能 quotaoff命令使用教程
82 1
|
6月前
|
Shell Linux C++
Linux C/C++ 开发(学习笔记二):Shell脚本编程案例
Linux C/C++ 开发(学习笔记二):Shell脚本编程案例
106 0
|
Shell
Shell脚本开发:printf和test命令的实际应用
Shell printf 命令 当你使用Shell中的printf命令时,它可以帮助你格式化和输出文本。 打印简单文本 这将简单地打印字符串"Hello, World!",并在末尾添加一个换行符\n来换行。 printf "Hello, World!\n" Shell test 命令 当你使用Shell中的test命令时,它用于测试条件是否为真(True)。test命令通常用于Shell脚本中的条件判断,以便根据条件的结果执行不同的操作。
58 1
|
6月前
|
存储 Shell Linux
【Shell 命令集合 磁盘管理 】Linux 启用指定文件系统上的磁盘配额功能 quotaon 命令使用教程
【Shell 命令集合 磁盘管理 】Linux 启用指定文件系统上的磁盘配额功能 quotaon 命令使用教程
74 1
|
分布式计算 Hadoop Java
17 案例:开发shell采集脚本
17 案例:开发shell采集脚本
90 0
|
6月前
|
分布式计算 Hadoop Shell
使用shell脚本实现自动SSH互信功能
使用shell脚本实现自动SSH互信功能
87 1
|
1月前
|
数据处理
基于ARM的嵌入式原理与应用:ALU的功能与特点
基于ARM的嵌入式原理与应用:ALU的功能与特点
|
3月前
|
编解码 安全 Linux
基于arm64架构国产操作系统|Linux下的RTMP|RTSP低延时直播播放器开发探究
这段内容讲述了国产操作系统背景下,大牛直播SDK针对国产操作系统与Linux平台发布的RTMP/RTSP直播播放SDK。此SDK支持arm64架构,基于X协议输出视频,采用PulseAudio和Alsa Lib处理音频,具备实时静音、快照、缓冲时间设定等功能,并支持H.265编码格式。此外,提供了示例代码展示如何实现多实例播放器的创建与管理,包括窗口布局调整、事件监听、视频分辨率变化和实时快照回调等关键功能。这一技术实现有助于提高直播服务的稳定性和响应速度,适应国产操作系统在各行业中的应用需求。
108 3
|
3月前
|
API C# Shell
WPF与Windows Shell完美融合:深入解析文件系统操作技巧——从基本文件管理到高级Shell功能调用,全面掌握WPF中的文件处理艺术
【8月更文挑战第31天】Windows Presentation Foundation (WPF) 是 .NET Framework 的关键组件,用于构建 Windows 桌面应用程序。WPF 提供了丰富的功能来创建美观且功能强大的用户界面。本文通过问题解答的形式,探讨了如何在 WPF 应用中集成 Windows Shell 功能,并通过具体示例代码展示了文件系统的操作方法,包括列出目录下的所有文件、创建和删除文件、移动和复制文件以及打开文件夹或文件等。
76 0