《嵌入式硬件(九):基于IMX6ULL的蜂鸣器操作》
一、链接脚本
内存段(Memory Segments)总结
1 .bss段
用于存放未初始化或初始化为0的数据
在运行时会被自动清零
典型例子:
static int bss_var; // 静态变量(全局或局部)int explicit_var = 0; // 显式初始化为0的全局变量
2. COMMON段
用于存放未初始化的非静态全局变量
链接时才确定最终大小和位置
允许多个目标文件定义同名符号
典型例子:
int common_var; // 未初始化的非静态全局变量
3. data段
用于存放已初始化的全局变量和静态变量(非零值)
需要在程序文件中保存实际的初始值
典型例子:
int global_var = 100; // 初始化为非零值int global_array[] = {1,2,3}; // 初始化为非零数组
4.rodata段(只读数据段)
存放程序的只读数据
运行时受保护,不可修改
包含的数据类型:
1) 字符串常量
2)const修饰的全局变量
3) 全局只读数组
4) switch跳转表
5) 浮点数常量
典型例子:
const int MAX_VALUE = 100; // const全局变量char* str = "Hello World"; // 字符串常量const int lookup[] = {1,2,3}; // 只读数组
各段的特点比较
段名 | 初始化 | 运行时可写 | 链接特性 |
---|---|---|---|
.bss | 自动清零 | 可写 | 编译时确定大小 |
COMMON | 自动清零 | 可写 | 链接时确定大小 |
.data | 需要初始值 | 可写 | 编译时确定大小 |
.rodata | 需要初始值 | 只读 | 编译时确定大小 |
关于段名中的通配符说明
在链接脚本中,经常会看到类似*(.rodata*)这样的写法,这里包含两个*通配符,它们有不同的含义:
1. 第一个`*`:
- 表示收集所有输入文件中的相关段
- 如果不加这个`*`,就只会收集特定文件的段
2. 第二个`*`(如`rodata*`中的`*`):
- 用于匹配所有以`.rodata`开头的段名
- 实际编译时会产生多种rodata相关的段,例如:
- `.rodata`:基本的只读数据段
- `.rodata.str1.1`:长度为1字节对齐的字符串常量
- `.rodata.str1.4`:长度为4字节对齐的字符串常量
- `.rodata.cst8`:8字节常量(如double类型的常量)
- `.rodata.cst4`:4字节常量(如float类型的常量)
如果只写`*(.rodata)`而不是`*(.rodata*)`:
- 只会收集严格命名为`.rodata`的段
- 其他相关的只读数据段(如`.rodata.str1.1`等)会被遗漏
- 这些被遗漏的数据可能导致程序无法正常工作
这种通配符的使用是链接脚本中的常见做法,类似的还有:
- `*(.text*)`:收集所有代码相关的段
- `*(.data*)`:收集所有数据相关的段
脚本代码
SECTIONS
{. = 0X87800000;.text :{obj/start.o*(.text)}.rodata ALIGN(4) : {*(.rodata*)}.data ALIGN(4) : {*(.data)}. = ALIGN(4) ;__bss_start = .;.bss ALIGN(4) : {*(.bss) *(COMMON)}__bss_end = .;
}
.为定位计数器,当前位置;ALIGN(4),四字节对齐; __bss_start = .和__bss_end = .保存bss段的地址,对他进行清零;
二、蜂鸣器原理
1.底板原理图
有源蜂鸣器:有震荡源,通过电流就响
低电平导通,响
需要把它的默认属性改为GPIO,要把他当外设
2.功能复用
3.电气属性
4.输入输出方向
5.数据寄存器
三、步骤
1)初始化时钟
2)设置引脚功能复用(GPIO)
3)引脚电气属性(功率、电阻)
4)设置外设引脚的输入输出方向
5)设置数据寄存器拉低/拉高电平
四、代码
1.结构
2.bsp
1)beep.c
#include "beep.h"
#include "fsl_iomuxc.h"void init_beep(void)
{IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0);IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0x10B0);GPIO5->GDIR |= (1 << 1);
}void beep_on(void)
{GPIO5->DR &= ~(1 << 1);
}void beep_off(void)
{GPIO5->DR |= (1 << 1);
}void beep_nor(void)
{GPIO5->DR ^= (1 << 1);
}
2)beep.h
#ifndef _BEEP_H_
#define _BEEP_H_extern void init_beep(void);
extern void beep_on(void);
extern void beep_off(void);
extern void beep_nor(void);#endif
3)led.c
4)led.h
3.project
1)main.c
#include "led.h"
#include "beep.h"
#include "MCIMX6Y2.h"void enable_clocks(void)
{CCM->CCGR0 = 0xFFFFFFFF;CCM->CCGR1 = 0xFFFFFFFF;CCM->CCGR2 = 0xFFFFFFFF;CCM->CCGR3 = 0xFFFFFFFF; CCM->CCGR4 = 0xFFFFFFFF;CCM->CCGR5 = 0xFFFFFFFF;CCM->CCGR6 = 0xFFFFFFFF;
}void delay(unsigned int n)
{while(n--);
}int main(void)
{enable_clocks();init_led();init_beep();while(1){led_nor();beep_nor();delay(0xFFFFF);}return 0;
}
2)start.S
.global _start_start:ldr pc, =_reset_handlerldr pc, =_undefine_handlerldr pc, =_svc_handlerldr pc, =_prefetch_abort_handlerldr pc, =_data_abort_handlerldr pc, =_reserved_handlerldr pc, =_irq_handlerldr pc, =_fiq_handler_undefine_handler:ldr pc, =_undefine_handler_svc_handler:ldr pc, =_svc_handler_prefetch_abort_handler:ldr pc, =_prefetch_abort_handler_data_abort_handler:ldr pc, =_data_abort_handler_reserved_handler:ldr pc, =_reserved_handler_irq_handler:ldr pc, =_irq_handler_fiq_handler:ldr pc, =_fiq_handler_reset_handler:mrs r0, cpsrbic r0, r0, #0x1Forr r0, r0, #0x12 //irqmsr cpsr, r0ldr sp, =0x80600000mrs r0, cpsrbic r0, r0, #0x1Forr r0, r0, #0x1F //systemmsr cpsr, r0 ldr sp, =0x80400000bl _bss_clearb main_bss_clear:ldr r0, =__bss_startldr r2, =__bss_end
loop:mov r1, #0str r1, [r0]add r0, r0, #4cmp r0, r2blt loopbx lrfinished:b finished