由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设计来说需要花时间去弥补。
======== ======\\ ======= -
|| || \\ // \\ /-\
|| || || // // \\
|| || // || // \\
====== ======= || === ========
|| || || \\ // \\
|| || \\ || // \\
|| || \\ // // \\
|| || ======= // \\
作者:绿叶落秋风,专注FPGA技术分析和分享,转载请注明原文链接:https://www.cnblogs.com/electricdream/p/12877932.html,文中资源链接如下:
1. GITHUB开源仓库