c语言指针项目实战案例嵌入式开发适用附完整代码

admin C语言 5


做嵌入式开发的朋友,是不是经常遇到这些问题?传感器采集的数据太多,内存不够用;想操作硬件寄存器,不知道怎么直接访问;函数之间传参,一大块数据拷贝来拷贝去,程序跑得越来越慢。其实啊,这些问题用指针都能解决。今天兔子哥就带一个嵌入式里常用的 “传感器数据采集与处理系统” 案例,手把手教你怎么用指针搞定这些麻烦,还附完整代码,一起往下看吧!


为啥嵌入式开发离不开指针?


嵌入式设备的内存一般都小,像单片机可能就几十 KB,要是不用指针,处理数据时动不动就复制来复制去,内存很快就不够用了。而且硬件寄存器地址是固定的,想操作它们,必须用指针直接访问。
比如说,你用 STM32 读取温湿度传感器,传感器的数据寄存器地址是 0x40001000,这时候就得用指针指向这个地址,才能读出里面的数据。要是不用指针,根本没法直接操作硬件,这就是嵌入式开发里指针的重要性。
可能有人会问,普通变量不行吗?还真不行。普通变量存在内存的随机位置,而硬件寄存器地址是固定的,只有指针能精准 “定位” 到这些地址。


实战案例:传感器数据采集与处理系统


这个案例模拟嵌入式设备采集多个传感器的数据(比如温度、湿度、光照),用指针来管理数据缓冲区、操作硬件地址、传递数据,代码在单片机上也能跑。
功能需求
  1. 读取 3 个传感器的数据(模拟硬件寄存器)
  2. 用环形缓冲区存储数据(节省内存)
  3. 处理数据(求平均值)并输出



第一步:用指针操作硬件寄存器


传感器的数据存在固定地址里,我们用指针直接访问这些地址来读数据。
c运行
// 模拟传感器寄存器地址(实际嵌入式开发中由硬件决定)#define TEMP_ADDR  (volatile unsigned short *)0x40001000#define HUMI_ADDR  (volatile unsigned short *)0x40001002#define LIGHT_ADDR (volatile unsigned short *)0x40001004// 读取传感器数据unsigned short read_temp() {return *TEMP_ADDR; // 用指针访问寄存器}unsigned short read_humi() {return *HUMI_ADDR;}unsigned short read_light() {return *LIGHT_ADDR;}

这里的volatile很重要,告诉编译器 “这个地址的数据可能会被硬件改变”,防止它优化掉读取操作。如果不加volatile,有时候读不到最新的传感器数据,程序就会出问题。


第二步:用指针管理环形缓冲区


采集到的数据要存在缓冲区里,环形缓冲区能循环利用内存,用指针来操作特别方便。
c运行
// 定义缓冲区结构体typedef struct {unsigned short data[10]; // 缓冲区大小unsigned short *head;    // 指向最新数据unsigned short *tail;    // 指向最旧数据unsigned char count;     // 数据个数} RingBuffer;// 初始化缓冲区void init_buffer(RingBuffer *buf) {buf->head = buf->data;buf->tail = buf->data;buf->count = 0;}// 存入数据(用指针移动实现环形)void put_data(RingBuffer *buf, unsigned short value) {*buf->head = value; // 存数据buf->head++;// 到头了就回到开头(环形)if (buf->head >= buf->data + 10) {buf->head = buf->data;}buf->count++;}

用指针headtail来跟踪数据位置,比用数组下标简洁多了。要是不用指针,每次移动位置都得算索引,代码会很啰嗦。


第三步:用指针传递数据,减少内存拷贝


处理数据时,我们需要把缓冲区的数据传给处理函数。用指针传地址,而不是传整个数组,能省很多内存。
c运行
// 求平均值(用指针访问缓冲区)unsigned short calc_avg(unsigned short *data, int len) {unsigned int sum = 0;for (int i = 0; i < len; i++) {sum += *(data + i); // 指针访问}return sum / len;}// 主函数流程int main() {RingBuffer temp_buf;init_buffer(&temp_buf);// 模拟采集10次温度数据for (int i = 0; i < 10; i++) {unsigned short temp = read_temp();put_data(&temp_buf, temp);}// 处理数据(传指针,不用复制整个数组)unsigned short avg = calc_avg(temp_buf.data, 10);// 输出结果(实际嵌入式中可能是打印到串口)printf("平均温度:%d\n", avg);return 0;}

这里calc_avg函数接收的是指针,直接访问缓冲区的数据,要是传整个数组temp_buf.data,就会复制 10 个元素,在内存小的设备上很不划算。


不用指针会怎样?


如果这个项目不用指针,会出现这些问题:
  1. 操作硬件寄存器时,得用编译器特定的扩展,代码不通用。
  2. 缓冲区管理要用大量的索引计算,容易出错。
  3. 函数传参复制数据,占用额外内存,程序变慢。

之前有个朋友做单片机项目,处理传感器数据时没用指针,结果数据量大一点就死机,后来改成指针操作,内存占用少了一半,程序也稳定了。


完整代码(可直接移植到嵌入式平台)


c运行
#include #include // 传感器寄存器地址#define TEMP_ADDR  (volatile uint16_t *)0x40001000#define HUMI_ADDR  (volatile uint16_t *)0x40001002#define LIGHT_ADDR (volatile uint16_t *)0x40001004// 环形缓冲区定义typedef struct {uint16_t data[10];uint16_t *head;uint16_t *tail;uint8_t count;} RingBuffer;// 初始化缓冲区void init_buffer(RingBuffer *buf) {buf->head = buf->data;buf->tail = buf->data;buf->count = 0;}// 存入数据void put_data(RingBuffer *buf, uint16_t value) {*buf->head = value;buf->head++;if (buf->head >= buf->data + 10) {buf->head = buf->data;}if (buf->count < 10) {buf->count++;}}// 读取传感器uint16_t read_temp() {return *TEMP_ADDR; // 实际硬件中这里会有真实数据}// 计算平均值uint16_t calc_avg(uint16_t *data, int len) {uint32_t sum = 0;for (int i = 0; i < len; i++) {sum += *(data + i);}return sum / len;}int main() {RingBuffer temp_buf;init_buffer(&temp_buf);// 模拟采集for (int i = 0; i < 10; i++) {// 实际中这里会有硬件延时uint16_t temp = read_temp();put_data(&temp_buf, temp);}uint16_t avg = calc_avg(temp_buf.data, temp_buf.count);printf("平均温度:%d\n", avg);return 0;}



兔子哥做嵌入式开发这么久,发现指针用得好不好,直接关系到程序的效率和稳定性。刚开始用指针可能会觉得麻烦,甚至经常出 bug,但熟练之后你会发现,很多棘手的问题用指针一处理就简单了。
这个案例里的环形缓冲区、硬件访问这些技巧,在实际项目中经常用到,你可以把代码拷过去,改改寄存器地址和缓冲区大小,就能用到自己的项目里。记住,嵌入式开发中,指针是帮你 “省内存、提速度” 的好工具,多练多用,自然就熟了。

标签: 数据采集 0x40001000

发布评论 0条评论)

  • Refresh code

还木有评论哦,快来抢沙发吧~