文章目录
简单编写实现一个裸板环境下使用的“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
来源:CSDN
作者:跑不了的你
链接:https://blog.csdn.net/qq_37596943/article/details/103867591