嵌入式C语言设计学习

Posted on 2020-05-14 20:38  绿叶落秋风  阅读(462)  评论(0编辑  收藏  举报

 由C语言到嵌入式C语言设计

1、C语言的特性

C语言,最为基本的高级编程语言,已经有许多其他的延伸。而在嵌入式设计中,主要的拓展内容就是相关的硬件设备的驱动。这部分的设计为其提供了更加灵活的应用环境。个人理解,嵌入式C的开发就是从电脑上的C转移到电路上的C。其最主要的设计思路就是寄存器配置。通过寄存器配置,可以实现各种外设与C语言(高级语言)直接相连,使之能够完成一些分散的任务。

2、学习内容

学会基本的C语言语法(学过的话就当复习用,反正忘得差不多了),了解嵌入C的设计思路,能够完成基本的设计内容。比如完成一些按键处理,一些外设驱动,UART传输处理结果等功能。

3、实际例子

学C的开端就是:hello world

#include <stdio.h>
int main()
{
  printf("hello world");
  return 0;   
}

这里也是从hello world开始的。外部的资源文件会由开发软件自动导入,我们所关注的就是源文件(也就是mian函数所在的地方)。先看一下基础代码:

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
int main()
{
 init_platform();
 printf("hello world");
 clean_platform();
 return 0;
}

从内容上看加入了两个新的头文件,第一个是工作区文件,可以看到主函数中有其数据调用的例子。printf则是由原来的向控制台输出文件转化为向UART输出文件。这里应该是xil_printf起到了作用。只需简单的几步,就完成了C向C嵌入的转化。看起来还是不难的。zynq使用的是ARM内核,肯定支持C的。事实上C应该是支持最广的高级语言。那么C的其他操作应该也是可以兼容的。比如计算、字符、文件以及其他的操作。以后有时间可以尝试一下。

看下一个例子:

#include <stdio.h>
#include "platform.h"
#include "xparameters.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xgpio.h"
#include <unistd.h> // usleep()
#include <stdbool.h> // bool
#define LED_DEVICE_ID XPAR_AXI_GPIO_1_DEVICE_ID
#define KEY_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID
XGpio LEDInst;
XGpio KEYInst;
u8 key_value_pre=0;
u8 key_value_now=0;
int main()
{
init_platform();
int status;
status = XGpio_Initialize(&KEYInst, KEY_DEVICE_ID); // initial KEY
if(status != XST_SUCCESS) return XST_FAILURE;
status = XGpio_Initialize(&LEDInst, LED_DEVICE_ID); // initial LED
if(status != XST_SUCCESS)return XST_FAILURE;
XGpio_SetDataDirection(&KEYInst, 1, 1); // set KEY IO direction as in
XGpio_SetDataDirection(&LEDInst, 1, 0); // set LED IO direction as out
XGpio_DiscreteWrite(&LEDInst, 1, 0x0);// at initial, all LED turn off
printf(">>> Press PL KEY1 ~ KEY4 one by one, and check the PL LED1 ~ LED4\n");
while(1)
{
usleep(100000); // 0.1s sleep, to debounce, in common, the meta-state will sustain
no more than 20ms
key_value_pre=key_value_now;
key_value_now= XGpio_DiscreteRead(&KEYInst, 1) & 0x0F;
XGpio_DiscreteWrite(&LEDInst, 1, key_value_now);
if(key_value_pre!=key_value_now) printf("key state_changed!\n");
}
cleanup_platform();
return 0;
}

以上代码源自小熊猫课堂

注意,这个代码运行于特定的硬件平台,不能移植到其他地方。这也是追求灵活性所必须付出的代价。至于两者如何取舍,则看个人的需求。这里代码就比较复杂了,还是从头文件开始分析。(和前面一样的就掠过了)

 xparameters.h:顾名思义就是参数定义库,是使用#define的基本头文件。这个功能学过编程语言的都知道,这里就不详述了。注意前面的#即可。

xscugic.h:可能是u8申明所需的库。

xil_exception.h:xilinx公司自己做的拓展包吧,具体在语法中讲。

xgpio.h:感觉是定义IO口的。

unistd.h:包含延时函数usleep

stdbool.h:布尔变量使用所需的库

看主程序的执行,C语言是顺序执行的,不要学了verilog就不会用C了。

初始化工作区init_platform();标准开头。

看XGpio_Initialize函数的用法,第一个参数是XGpio变量的地址,第二个是AXI总线分配的地址。合起来就是将AXI-GPIO这个IP核的信号转化为宏(也有可能是结构体)并且初始化。使用一个int变量表示其状态。用于判断是否总线有效。

而下面的while就比较好理解了。就是储存前一状态和现状态比较,不同就输出URAT。同时LED输出跟随key。

主要的难点在于这个结构体的声明,需要从硬件设计中拿到分配的地址,需要了解XGpio的各种访问函数。

这点可能对于C设计来说需要花时间去弥补。