完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异。
1.从两个使用过的角度来讲: 使用固件库,目前比较多的例程是使用固件库编写的。官方的例子也都采用固件库方式。特点就是简单,易于理解,资料多。如果你没有CortexM系列内核的开发基础,建议从固件库开始玩起。等有一定基础,或是特别需要时再用寄存器。 使用寄存器,想要深入理解CortexM3内核或是需要为了获得更好的可移植性,学习寄存器编程会比较有帮助。但是从专业的角度上看,寄存器更贴近底层,对外设的工作原理和运行机理会有更深的理解。 2.从直观角度来讲: (1)寄存器–比较直观的感觉就是,寄存器版式直接对内部寄存器进行操作,需要我们对寄存器非常熟悉 (2)库函数–是用ST提供的库函数开发,有函数的集合,不需要与寄存器直接打教导,提供用户函数调用的API 3.从实际操作来讲: (1)寄存器 下列操作语句为寄存器的特点: GPIOB->CRL&=0XFFOFEFFE; GPIOB->CRL1=0X00300000; (2)库函数: 两者对照来看,库函数比寄存器多了FWLIB里面的函数,这就是上面提到过的,ST提供的库函数,给用户提供函数的了API接口。例如对函数库的调用如下: GPIO SetBits(GPIOB, GPIO_Pin_5); GPIO ResetBits(GPLOB, GPIO_Pin_5); STM32的USART窗口通讯程序 1.配置库函数 (这些都是厂家配置好了的,不需要我们在进行配置操作) 2.部分函数介绍 本次实验主要运用的主要是SYSTEM下的串口部分:usart_init函数: 然后比较主要的函数就是中断函数USART1_IRQHandler,这里不做介绍,可查询资料。 3.相关硬件 这里使用的是: (1)正点原子stm32开发板 (2)USB转TTL (3)J-Link下载器 4.实操 做一些初始化操作:设置NVIC中断 分组2:2抢占优先级,2位响应优先级。之后初始化串口,根据要求串口初始化位115200,然后初始化按键,然后初始化LED,作用就是显示程序在板子上是否正常运行。 之后进入函数的主体:先是给上位机发送Hello Windows,由于一直发送太快了,所以就做了一个延时才发送;为了方便控制发送与停止,我设置了标记变量flag,如果发送停止标记,那么flag置1。我把Hello Windows放置在一个数组中,而结束标志stop stm32放在另一个数组中。 发送由下代码: USART_SendData(USART1,p[t]);//向串口1发送数据while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束 由接收的话可以由USART_RX_STA来得知,测得得出数据的长度,先在上位机上显示,然后比较是否为结束指令,如果是,就改变标记。 这样,就能成功实现,1、发送给上位机Hello Windows 2、上位机发送stop stm32就停止。 5.效果演示 6.程序代码: #include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "usart.h" #include "beep.h" int main(void) { u16 t; u16 len; u16 times=0; char *p=" Hello Windows"; u8 *q="stop stm32"; u8 flag=0; //标志如果是1的话,停止发送数据 BEEP_Init(); //初始化蜂鸣器不响 delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 KEY_Init(); //初始化与按键连接的硬件接口 while(1) { //给上位机连续发送Hello Windows if(!flag) { times++; if(times%100==0) { len=14; for(t=0;t USART_SendData(USART1,p[t]);//向串口1发送数据 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束 } printf("rnrn");//插入换行 USART_RX_STA=0; } if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行. delay_ms(10); } //接收上位机的发送,并判断是否停止 if(USART_RX_STA&0x8000) { //显示消息 len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度 printf("rn收到消息为:nr"); for(t=0;t printf("%c",USART_RX_BUF[t]);//接收得到的数据 } printf("rn");//插入换行 //判断是否停止发送 for(t=0;t<10;t++) if(q[t]!=USART_RX_BUF[t])//如果出现不等,那么就继续发送 { flag=0; break; } if(t==10)//如果都相等,那么停止发送 { flag=1; printf("已收到停止,现在停止发送!"); break; } printf("rnrn");//插入换行 USART_RX_STA=0; } } } 7.总结 通过对STM32串口通信的实验,我学习到很多stm32串口通信的操作以及知识。对于实体班子的操作是一件很有趣的事情,这个过程熟悉了函数库,直接通过调函数来实现十分方便。 C语言程序里全局变量、局部变量、堆、栈等概念 #include #include #include void before() { } char g_buf[16]; char g_buf2[16]; char g_buf3[16]; char g_buf4[16]; char g_i_buf[]="123"; char g_i_buf2[]="123"; char g_i_buf3[]="123"; void after() { } int main(int argc, char **argv) { char l_buf[16]; char l_buf2[16]; char l_buf3[16]; static char s_buf[16]; static char s_buf2[16]; static char s_buf3[16]; char *p_buf; char *p_buf2; char *p_buf3; p_buf = (char *)malloc(sizeof(char) * 16); p_buf2 = (char *)malloc(sizeof(char) * 16); p_buf3 = (char *)malloc(sizeof(char) * 16); printf("g_buf: 0x%xn", g_buf); printf("g_buf2: 0x%xn", g_buf2); printf("g_buf3: 0x%xn", g_buf3); printf("g_buf4: 0x%xn", g_buf4); printf("g_i_buf: 0x%xn", g_i_buf); printf("g_i_buf2: 0x%xn", g_i_buf2); printf("g_i_buf3: 0x%xn", g_i_buf3); printf("l_buf: 0x%xn", l_buf); printf("l_buf2: 0x%xn", l_buf2); printf("l_buf3: 0x%xn", l_buf3); printf("s_buf: 0x%xn", s_buf); printf("s_buf2: 0x%xn", s_buf2); printf("s_buf3: 0x%xn", s_buf3); printf("p_buf: 0x%xn", p_buf); printf("p_buf2: 0x%xn", p_buf2); printf("p_buf3: 0x%xn", p_buf3); printf("before: 0x%xn", before); printf("after: 0x%xn", after); printf("main: 0x%xn", main); if (argc > 1) { strcpy(l_buf, argv[1]); } return 0; } 该代码定义了全局变量并输出它们的地址 再输入: #include #include //定义全局变量 int init_global_a = 1; int uninit_global_a; static int inits_global_b = 2; static int uninits_global_b; void output(int a) { printf("hello"); printf("%d",a); printf("n"); } int main( ) { //定义局部变量 int a=2; static int inits_local_c=2, uninits_local_c; int init_local_d = 1; output(a); char *p; char str[10] = "lyy"; //定义常量字符串 char *var1 = "1234567890"; char *var2 = "qwertyuiop"; //动态分配 int *p1=malloc(4); int *p2=malloc(4); //释放 free(p1); free(p2); printf("栈区-变量地址n"); printf(" a:%pn", &a); printf(" init_local_d:%pn", &init_local_d); printf(" p:%pn", &p); printf(" str:%pn", str); printf("n堆区-动态申请地址n"); printf(" %pn", p1); printf(" %pn", p2); printf("n全局区-全局变量和静态变量n"); printf("n.bss段n"); printf("全局外部无初值 uninit_global_a:%pn", &uninit_global_a); printf("静态外部无初值 uninits_global_b:%pn", &uninits_global_b); printf("静态内部无初值 uninits_local_c:%pn", &uninits_local_c); printf("n.data段n"); printf("全局外部有初值 init_global_a:%pn", &init_global_a); printf("静态外部有初值 inits_global_b:%pn", &inits_global_b); printf("静态内部有初值 inits_local_c:%pn", &inits_local_c); printf("n文字常量区n"); printf("文字常量地址 :%pn",var1); printf("文字常量地址 :%pn",var2); printf("n代码区n"); printf("程序区地址 :%pn",&main); printf("函数地址 :%pn",&output); return 0; } 通过运行结果可以发现,Ubuntu在栈区和堆区的地址值都是从上到下依次增大的 stm32的堆、栈、全局变量的分配地址 之前串口通信模板,把main.c改为如下: #include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "usart.h" #include "beep.h" static unsigned int val1 = 1; //data段 unsigned int val2 = 1; //初始化的全局变量data段 unsigned int val3 ; //未初始的在bsss段 const unsigned int val4 = 1; //常量在rodata段,只读 unsigned char Demo(unsigned int num) { char var; //栈区,123456,存放在常量区 unsigned int num1=1; //栈区 static unsigned int num2=0; //,data段 const unsigned int num3 =7; //栈区 printf("val1: 0x%xrn",&val1); printf("val2: 0x%xrn",&val2); printf("val3: 0x%xrn",&val3); printf("val4: 0x%xrn",&val4); printf("var: 0x%xrn",&var); printf("num1: 0x%xrn",&num1); printf("num2 0x%xrn",&num2); printf("num3: 0x%xrn",&num3); return 1; } int main(void) { unsigned int num=0; BEEP_Init(); //初始化蜂鸣器不响 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 num = Demo(num); //返回值存放在栈区 } 经过keil编译 存放了Code、RO-data、RW-data、ZI-data四个代码段的大小。其中Code就是代码占用大小,RO-data是只读常量、RW-data是已初始化的可读可写变量,ZI-data是未初始化的可读可写变量。 生成hex文件,录入板子,经过串口发送后得到变量地址,打开上位机显示后如下: 查看STM32地址分配: ROM的地址分配是从0x8000000开始,整个大小为0x80000,这个部分用于存放代码区和文字常量区。RAM的地址分配是从0x20000000开始,其大小是0x10000,这个区域用来存放栈、堆、全局区(.bss段、.data段)。与代码结果显示进行对比,也可以看出对应得部分得地址与设置的是相对应的。 结合来看,可以大概看出栈在顶层(地址最大),然后依次是堆,静态区。对比以下地址分配图,大致符合。 Keil下Code、RO-data、RW-data、ZI-data 这几个段 1.Code是存储程序代码的; 2.RO-data是存储const常量和指令 3.RW-data是存储初始化值不为0的全局变量 4.ZI-data是存储未初始化的全局变量或初始化值为0的全局变量 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1617 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1543 浏览 1 评论
977 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
683 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1595 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
531浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
504浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 05:06 , Processed in 0.751674 second(s), Total 77, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号