揭阳商城网站建设中国新闻社待遇
news/
2025/10/4 9:48:01/
文章来源:
揭阳商城网站建设,中国新闻社待遇,ui中国设计官网,浙江省城乡住房建设部网站汇编怎么调用C函数
直接调用
BL main传参数 在arm中有个ATPCS规则#xff08;ARM-THUMB procedure call standard#xff09;#xff08;ARM-Thumb过程调用标准#xff09;。
约定r0-r15寄存器的用途#xff1a;
r0-r3#xff1a;调用者和被调用者之间传递参数r4-r11…汇编怎么调用C函数
直接调用
BL main传参数 在arm中有个ATPCS规则ARM-THUMB procedure call standardARM-Thumb过程调用标准。
约定r0-r15寄存器的用途
r0-r3调用者和被调用者之间传递参数r4-r11函数可能被使用所以在函数的入口保存它们在函数的出口恢复它们。 int delay(unsigned int d)
{while(d--);return 0;
}ldr r0,1000000
dl delay
cmp r0,#0 返回值保存在r0
A函数调用B函数 假设A函数里需要用到R4寄存器B函数里也需要用到R4寄存器。 因此B函数就有会覆盖A函数R4寄存器的值。
于是需要在B函数执行前保存R4-R11寄存器的值在A的栈中 。 B函数执行完后返回A函数前要从A的栈中恢复R4-R11寄存器。
C函数的反汇编码阅读
要解决几个问题
为什么调用C函数前要设置栈栈的作用是C函数传参C函数执行过程 反汇编示例 地址0x08000010Flash上烧写20010000。
启动流程
上电后
设置栈CPU会从0x08000000读取值用来设置SP我们的程序里再次设置了SP。跳转CPU会从0x08000004得到地址值根据它的BIT0切换到ARM状态或Thumb状态然后跳转。
对于Cortex M3/M4它只支持Thumb状态所以0x08000004上的值bit0必定是1。 对0x08000004上的值Reset_Handler1。 从Reset_Handler上继续执行
纯汇编点灯 写程序
寄存器操作 对于寄存器的操作主要涉及读、修改、写。
读可以使用LDR指令代码为LDR R1,[R0]写使用STR指令代码为STR R1,[R0]修改清除位使用BIC或AND指令设置位使用ORR指令
LDR R0, (120) | (121)
BIC R1,R1,R0 ;清除R1的bit20bit21
LDR R0, (120)
ORR R1,R1,R0 设置R1的bit20函数里的条件判断 比如减1操作代码为SUB R0,R0,#1 顺便使用减1后的结果影响程序状态寄存器代码为SUBS R0,R0,#1程序的调用与返回值 传参代码为LDR R0,VAL 调用代码为BL delay它顺便把下一条指令的地址保存在LR寄存器了。 返回代码为MOV PC,LR
使用按键控制LED 先看原理图我们使用KEY1来控制红色LED按下KEY1在灯亮松开后灯灭。 KEY1的引脚是PA0
使能GPIOA模块RCC_APB2ENR0x400210000x18
串口的硬件介绍
UART的全称是Universal Asynchronous Receiver and Transmitter即通用异步收发器。 串口在嵌入式中用途非常的广泛主要的用途有
打印调试信息外接各种模块GPS、蓝牙
串口因为结构简单、稳定可靠广受欢迎。
通过三根线即可发送、接收、地线。 TXD线把PC机要发送的信息发送给ARM开发板。 最下面的地线统一参考地。
串口的参数
波特率一般选波特率都会有9600、19200、115200等选项。其实意思就是每秒传输这么多个比特位数bit。起始位先发出一个逻辑0的信号表示传输数据的开始。数据位可以是5~8位逻辑0或1.如ASCII码7位、扩展BCD码8位。小端传输。校验位数据位加上这一位后使得1的位数应为偶数偶校验或奇数奇校验以此来校验数据传送的正确性。停止位它是一个字符数据的结束标志。
怎么发送一字节数据比如A A’的ASCII值是0x41二进制就是0x01000001怎么把这8位数据发送给PC机呢
双方约定好波特率每一位占据的时间规定传输协议 原来是高电平ARM拉低电平保持1bit时间。 PC在低电平处开始计时。 ARM根据数据依次驱动TXD电平同时PC依次读取RXD电平获得数据。 PC机在数据位的中间读取引脚状态。 RS-232的电平比TTL/CMOS高能传输更远的距离在工业上用得比较多。
市面上大多数ARM芯片都不止一个串口一般使用串口0来调试其它串口来外接模块。 115200,8n1。 一秒钟可以传输115200个bit传送一个字节需要1个起始位8个数据位1个停止位10bit。 所以一秒钟可以传输11520个字节。
UART编程
看原理图确定引脚
有很多串口使用哪一个看原理图确定。配置引脚为UART功能 至少用到发送、接收引脚txd、rxd 需要把这些引脚配置为UART功能并使能UART模块设置串口参数根据状态寄存器读写数据 肯定有一个数据寄存器程序把数据写入即可通过串口向外发送数据。 肯定有一个数据寄存器程序读取这个寄存器就可以获得先前接收到的数据。 很多有状态寄存器判断数据是否发送出去是否发送成功判断是否接收到了数据 需要使能GPIOA/USART1模块 需要设置GPIOA的寄存器选择引脚功能所以要使能GPIOA模块。 GPIOA模块、USART1模块的使能都是在同一个寄存器里实现。 USART寄存器用结构体来表示比较方便
typedef unsigned int uint32_t;
typedef struct
{volatile uint32_t SR; /*! USART Status register, Address offset: 0x00 */volatile uint32_t DR; /*! USART Data register, Address offset: 0x04 */volatile uint32_t BRR; /*! USART Baud rate register, Address offset: 0x08 */volatile uint32_t CR1; /*! USART Control register 1, Address offset: 0x0C */volatile uint32_t CR2; /*! USART Control register 2, Address offset: 0x10 */volatile uint32_t CR3; /*! USART Control register 3, Address offset: 0x14 */volatile uint32_t GTPR; /*! USART Guard time and prescaler register, Address
}USART_TypeDef;
USART_TypeDef *usart1 (USART_TypeDef *)0x40013800;在C语言中编译器通常会对代码进行各种优化以提高程序的执行效率。这些优化包括重新排序指令、删除看似无用的变量读取等。
然而在与硬件通信的情景下有些变量的值可能会被硬件或者其他事件异步地修改而这种修改通常是在程序控制流之外发生的。
假设有一个代表硬件寄存器的变量如果没有使用’volatile’关键字编译器可能会进行一些优化认为这个变量的值在程序的某个地方被设置后就不再改变。这就可能导致一些问题因为实际上这个变量的值可能会在程序的其它地方被异步地修改。
通过在变量声明中加入’volatile’关键字告诉编译器不要对这个变量进行过多的优化以确保每次访问这个变量时都从内存中读取最新的值而不是使用之前缓存的值。 这对于与硬件直接交互的变量比如你提供的USART通信寄存器非常重要因为这些寄存器的值可能会在程序的正常流程之外被外部事件改变。
#ifndef __UART_H
#define __UART_Hvoid uart_init();
char getchar();
char putchar(char c);#endif这段代码是一种常见的C/C预处理器约定用于防止头文件header file被多次包含避免引起重定义错误。
#ifndef这是预处理指令表示if not defined即如果之前没有定义过指定的标识符那么执行接下来的代码。__UART_H这是一个宏标识符通常是头文件名的大写形式加上双下划线前缀以确保标识符的唯一性。在这里它用于作为一个宏防止头文件被多次包含。#define __UART_H如果之前没有定义过__UART_H那么用这个#define指令定义它。这样当头文件再次被引用时#ifndef检查将会失败因为__UART_H已经被定义了。#endif表示条件编译的结束。如果之前#ifndef条件成立那么在这里结束条件编译块。
这种写法的目的是确保一个头文件只会被编译一次即使它在多个地方被引用。这可以防止由于头文件被重复引用而导致的重定义错误。这是一种预防措施用于提高代码的可维护性和可移植性。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/926987.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!