stm32学习 c语言笔记
STM32中C语言知识点:初学者必看

这个例子中只有几行代码,我们很快就可以找到程序蹦的原因就是变 量 c 的值为 0。但是,如果代码量很大,我们还能这么快的找到问题 点吗? 这时候,assert()就派上用场了,以上代码中,我们可以在 a = b / c;这 句代码之前加上 assert(c);这句代码用来判断变量 c 的有效性。此时, 再编译运行,得到的结果为:
// ...... #endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
#if 的使用一般使用格式如下 #if 整型常量表达式 1
程序段 1 #elif 整型常量表达式 2
程序段 2 #else
程序段 3 #endif
执行起来就是,如果整形常量表达式为真,则执行程序段 1,以此类 推,最后#endif 是#if 的结束标志。 (2)#ifdef、#ifndef
我们使用#pragma pack 指令来指定对齐的字节数。例子: ①指定按 1 字节对齐
运行结果为:
②指定 2 字节对齐
运行结果为:
可见,指定的对齐的字节数不一样,得到的结果也不一样。指定对齐 有什么用呢,大概就是可以避免了移植过程中编译器的差异带来的代 码隐患吧。比如两个编译器的默认对齐方式不一样,那可能会带来一 些 bug。 (2)#pragma message 该指令用于在预处理过程中输出一些有用的提示信息,如:
可见,程序蹦的同时还会在标准错误流中打印一条错误信息: Assertion failed:c, file hello.c, line 12 这条信息包含了一些对我们查找 bug 很有帮助的信息:问题出在变 量 c,在 hello.c 文件的第 12 行。这么一来,我们就可以迅速的定位 到问题点了。 这时候细心的朋友会发现,上边我们对 assert()的介绍中,有这么一 句说明: 如果表达式的值为假,assert()宏就会调用_assert 函数在标准错误流 中打印一条错误信息,并调用 abort()(abort()函数的原型在 stdlib.h 头文件中)函数终止程序。 所以,针对我们这个例子,我们的 assert()宏我们也可以用以下代码 来代替: if (0 == c) { puts("c 的值不能为 0,请重新输入!"); abort(); }
stm32自学笔记共20页

•
LED0=1;
•
LED1=0;
•
delay_ms(300);
•
}
•}
第二章 跑马灯实验
• Led.c函数
• void LED_Init(void)
•{
•
RCC->APB2ENR|=1<<2; //使能PORTA时钟
•
GPIOA->CRH|=0XFFFFFFFF3;//PA8 推挽输出
•
GPIOA->ODR|=1<<8; //PA8 输出高
• JTAG_Set(JTAG_SWD_DISABLE);//关闭JTAG和SWD,在原理图上可以看 到PA13和PA15为键盘和JTAG与SWD所共用,而这两种方针接口,他们 和普通的IO口公用,当想使用普通IO口时,必须先把他们关闭。在这 个函数里面设置参数,如果为二进制数00,则代表全部使能,如果是 二进制数01,则是能SWD,如果是10,则表示全部关闭。JTAG是一种 国际标准测试协议,主要用于芯片内部的测试。
• }要想实现一个点亮led小灯的功能,最少只需对3个寄存器进行设 置,第一步是设置外设时钟使能先把PORTA时钟使能,接下来把IO
口设置为输出,在接下来设置输出为高电平还是低电平,这里使用 推挽输出(3.3v),推挽输出主要是增强驱动能力,为外部提供大电 流。
第二章 跑马灯实验
• #ifndef __LED_H • #define __LED_H • #include "sys.h" • #define LED0 PAout(8)// PA8 • #define LED1 PDout(2)// PD2 • void LED_Init(void);//初始化
STM32学习笔记

串口:一. USART_ITConfig(USART1, USART_IT_TXE, ENABLE):只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开。
二.以下是字符发送的配置过程,注意第6点,在设置USART_CR1中的TE位时,会发送一个空闲帧作为第一次数据发送,所以即便你执行了USART_ClearFlag(USART1, USART_FLAG_TC); (这个函数肯定在空闲帧数据发送完成前执行),所以当空闲帧发送完后,就进入发送完成中断。
配置步骤:1. 通过在USART_CR1寄存器上置位UE位来激活USART2. 编程USART_CR1的M位来定义字长。
3. 在USART_CR2中编程停止位的位数。
4. 如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMA T)。
按多缓冲器通信中的描述配置DMA寄存器。
5. 利用USART_BRR寄存器选择要求的波特率。
6. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。
7. 把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。
在只有一个缓冲器的情况下,对每个待发送的数据重复步骤7。
8. 在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的传输结束。
当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏最后一次传输。
解决的办法:方法一在执行USART_ITConfig(USART1, USART_IT_TC, ENABLE); 之前,先延时一段时间,基本上比一个字符发送的时间长一点就可以了,然后再执行USART_ClearFlag(USART1, USART_FLAG_TC);方法二:在执行USART_ITConfig(USART1, USART_IT_TC, ENABLE); 之前,USART_ClearFlag(USART1, USART_FLAG_TC);while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET){; //等待空闲帧发送完成后再清零发送标志}USART_ClearFlag(USART1,USART_FLAG_TC);三.TXE:发送缓冲器空闲标志RXNE:接收缓冲区非空IAP:一.问:这几天在折腾STM32的IAP,参考了两个例程,一个AN2557,然后一个就是标准外设库内的flash例程总结IAP:1.Flash解锁 FLASH_Unlock();2.清除Flash所有的未完成的标志位 FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);3.根据文件大小擦除Flashfor(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE ); EraseCounter++){FLASHStatus = FLASH_ErasePage(StartAddr + (FLASH_PAGE_SIZE * EraseCounter));}4.编程Flashwhile((Address < EndAddr) && (FLASHStatus == FLASH_COMPLETE)){FLASHStatus = FLASH_ProgramWord(Address, Data);Address = Address + 4;}5.检验编入数据的正确性while((Address < EndAddr) && (MemoryProgramStatus != FAILED)){if((*(__IO uint32_t*) Address) != Data){MemoryProgramStatus = FAILED;}Address += 4;}在以上几步中,如果上面没有问题的话,提出下面几个疑问1.假如我的应用程序的地址应该从0x8003000开始,那么我把后面的页全部擦除是否可以? 虽然我的程序可能只占到0x8003000-0x8005000 那么这之后的页是否也可以一并擦除?2.在编程的时候有个很小的问题,因我的数据都是以字节(byte)的形式储存的,在写的时候因为只能以半字(16位)或一个字(32位)的方式编程,那么如果我的bin文件的最后一个字节并不够两个字节,怎么办?举例:我的bin文件的大小是501个字节(8位),我的写入方法是这样的:data[501] = {X,X,X...}//应用程序bin文件内容temp = data[0];temp = temp << 8;temp |= data[1];temp = temp << 8;temp |= data[2];teme = temp << 8;teme |= data[3];//待写入得数据FLASHStatus = FLASH_ProgramWord(Address, temp);//写入flash如果像这样的话,那么不能被4整除的那一个字节怎么办?3.IAP程序中有一处一直很迷惑,不能理解/* Test if user code is programmed starting from address "ApplicationAddress" */if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000){ /* Jump to user application */JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);Jump_To_Application = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) ApplicationAddress);Jump_To_Application();}程序的整体是要跳出IAP引导区跳到应用程序区.那么这句判断的依据是什么?if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)倘若我今天的程序是重0x8003000处开始,那么明天我升级一个程序,他的开始是0x80080000呢?这里需要改吗?0x2FFE0000 0x20000000 这两个数我在AN2557的例子代码里反复寻找,并没有哪里出现,那么又是怎么跟用户的应用程序关联的呢?还有如果将上面的例子直接这样更改,是否可以达到跳转到应用程序区的目的呢?/* Jump to user application */JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); //这里为何要+4 ?+了4不就跳过出应用程序的入口了吗?Jump_To_Application = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) ApplicationAddress);Jump_To_Application();4.关于Flash的写保护问题,在3.0标准外设库中Flash还有另外一个例子,就是关于保护的无疑flash的保护是对程序的一个安全保障,但目前我买的新片子(未进行过任何保护方面的操作)中,是否不需要考虑这些问题,直接擦除,然后编程即可?5.有什么理由要“今天的程序是重0x8003000处开始,明天又升级一个程序,他的开始是呢”?第1没有必要,第2是自寻烦恼。
STM32学习笔记

STM32学习一、初识库(略)二、(略)三、(略)四、(略)五、(略)六、系统定时器1、注意外部函数的声明;2、与六相同,也使用了中断;3、Volatile是不让编译优化的意思;4、Extern即定义外部函数,static是静态变量的意思。
七、串口通信1、当使用printf时,记得要在“bsp_usart1.h”文件中把“stdio.h”包含进来2、NVIC是中断优先级配置函数3、注意使用微库右图中的Use Micro LIB要打勾4、八、DMA1、DMA含义:data memory access,直接内存访问,此时不经过CPU2、这种方式节省CPU资源,好像可以同时做两件事(ADC、SPI、I2C等),不同的外设通道不同,可参看数据手册,串口1是通道4九、ADC1、ADC为12位,时钟为14MHz,最小采样时间为1微秒2、要提高采集频率,可采用多通道交叉采样。
十、FSMC液晶显示1、FSMC含义:灵活的静态存储器控制器2、注意配置IO引脚的第二功能时应注意配置成“AF-pp”即复用推挽模式;3、注意片选BANK1-44、野火自带的屏的高度840,宽320十一、I2C总线1、I2C一般都是开漏输出2、一般向I2C写数据时,如不加限制,是从头开始,写到本页结束如果再写又回到本页开头,会覆盖原来内容,因此,为避免这种情况,加地址。
十二、SPI总线1、SPI总线的读写速度(特别是读速度)要比对SD卡的快,而且成本低;2、SPI总线模块可存汉字字库、图片等,一些掉电保护信息也可存于此;3、在“bsp_spi_flash.c”中,语句“RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_GPIOD, ENABLE);”中的D端口时钟不需要开,即“RCC_APB2Periph_GPIOD”是不必要的,可以删去;4、“sizeof()”是C语言的保留字,其用法在此有描述。
STM32入门C语言详解

阅读flas h:芯片内部存储器flas h操作函数我的理解——对芯片内部f lash进行操作的函数,包括读取,状态,擦除,写入等等,可以允许程序去操作fl ash上的数据。
基础应用1,FLASH时序延迟几个周期,等待总线同步操作。
推荐按照单片机系统运行频率,0—24MHz时,取Laten cy=0;24—48MHz时,取Laten cy=1;48~72MHz时,取Laten cy=2。
所有程序中必须的用法:FLASH_SetLa tency(FLASH_Laten cy_2);位置:RCC初始化子函数里面,时钟起振之后。
基础应用2,开启FLAS H预读缓冲功能,加速FLAS H的读取。
所有程序中必须的用法:FLASH_Prefe tchBu fferC md(FLASH_Prefe tchBu ffer_Enabl e);位置:RCC初始化子函数里面,时钟起振之后。
3、阅读lib:调试所有外设初始化的函数。
我的理解——不理解,也不需要理解。
只要知道所有外设在调试的时候,EWRAM需要从这个函数里面获得调试所需信息的地址或者指针之类的信息。
基础应用1,只有一个函数debug。
所有程序中必须的。
用法: #ifdefDEBUGdebug();#endif位置:main函数开头,声明变量之后。
4、阅读nvic:系统中断管理。
我的理解——管理系统内部的中断,负责打开和关闭中断。
基础应用1,中断的初始化函数,包括设置中断向量表位置,和开启所需的中断两部分。
所有程序中必须的。
用法: void NVIC_C onfig urati on(void){NVIC_I nitTy peDef NVIC_I nitSt ructu re; //中断管理恢复默认参数#ifdefVECT_T AB_RA M //如果C/C++ Compil er\Prepro cesso r\Define d symbol s中的定义了VECT_TAB_RAM(见程序库更改内容的表格)NVIC_S etVec torTa ble(NVIC_V ectTa b_RAM, 0x0); //则在RAM调试#else //如果没有定义VECT_TAB_R AMNVIC_S etVec torTa ble(NVIC_V ectTa b_FLA SH, 0x0);//则在Flas h里调试#endif//结束判断语句//以下为中断的开启过程,不是所有程序必须的。
stm32学习笔记(狼牙整理)

系统时钟 SYSCLK 最大频率为 72MHz,它是供 STM32 中绝大部分部件工作的时钟源。 系统时钟可由 PLL、HSI 或者 HSE 提供输出,并且它通过 AHB 分频器分频后送给各模 块使用,AHB 分频器可选择 1、2、4、8、16、64、128、256、512 分频。其中 AH B 分频器输出的时钟送给 5 大模块使用:①、送给 AHB 总线、内核、内存和 DMA 使用 的 HCLK 时钟。 ②、分频后送给 STM32 芯片的系统定时器时钟(Systick=Sysclk/8=9Mhz) ③、直接送给 Cortex 的自由运行时钟(free running clock)FCLK。【ARMJISHU 注:FCL K 为处理器的自由振荡的处理器时钟,用来采样中断和为调试模块计时。在处理器休眠时, 通过 FCLK 保证可以采样到中断和跟踪休眠事件。 Cortex-M3 内核的“自由运行时钟(fre e running clock)”FCLK。“自由”表现在它不来自系统时钟 HCLK,因此在系统时钟停 止时 FCLK 也继续运行。FCLK 和 HCLK 互相同步。FCLK 是一个自由振荡的 HCLK。FCL K 和 HCLK 应该互相平衡,保证进入 Cortex-M3 时的延迟相同。】④、送给 APB1 分频 器。APB1 分频器可选择 1、2、4、8、16 分频,其输出一路供 APB1 外设使用(PCLK1, 最大频率 36MHz),另一路送给定时器(Timer)2、3、4 倍频器使用。该倍频器可选择 1 或 者 2 倍频,时钟输出供定时器 2、3、4 使用。 ⑤、送给 APB2 分频器。APB2 分频器可选择 1、2、4、8、16 分频, 其输出一路供 APB 2 外设使用(PCLK2,最大频率 72MHz),另一路送给定时器(Timer)1 倍频器使用。该倍频
stm32--C语言

1.12,最易变的关键字----volatilevolatile是易变的、不稳定的意思。
很多人根本就没见过这个关键字,不知道它的存在。
也有很多程序员知道它的存在,但从来没用过它。
我对它有种“杨家有女初长成,养在深闺人未识”的感觉。
volatile关键字和const一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。
遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
先看看下面的例子:int i=10;int j = i;//(1)语句int k = i;//(2)语句这时候编译器对代码进行优化,因为在(1)、(2)两条语句中,i 没有被用作左值。
这时候编译器认为i 的值没有发生改变,所以在(1)语句时从内存中取出i的值赋给j 之后,这个值并没有被丢掉,而是在(2)语句时继续用这个值给k赋值。
编译器不会生成出汇编代码重新从内存里取i 的值,这样提高了效率。
但要注意:(1)、(2)语句之间i没有被用作左值才行。
再看另一个例子:volatile int i=10;int j = i;//(3)语句int k = i;//(4)语句volatile关键字告诉编译器i是随时可能发生变化的,每次使用它的时候必须从内存中取出i 的值,因而编译器生成的汇编代码会重新从i 的地址处读取数据放在k 中。
这样看来,如果i 是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说volatile可以保证对特殊地址的稳定访问。
但是注意:在VC++6.0中,一般Debug模式没有进行代码优化,所以这个关键字的作用有可能看不出来。
你可以同时生成Debug版和Release版的程序做个测试。
2、定义const只读变量,具有不可变性。
const int *p; // p 可变,p指向的对象不可变int const *p; // p可变,p指向的对象不可变int*constp; //p不可变,p指向的对象可变const int *const p; //指针p和p指向的对象都不可变在平时的授课中发现学生很难记住这几种情况。
STM32学习笔记小结

STM32学习笔记目录STM32学习笔记 (1)一、入门 (2)目标->实战项目 (2)STM32学习方法 (3)ARM简介 (4)二、外设功能模块 (5)GPIO原理与工作模式 (5)串行通信 (6)硬件下载与调试 (6)Cortex-M3复用功能(AF)和重映射功能 (6)Systick的使用 (7)通用定时器 (7)SPI与数码管 (7)I2C通信 (8)NVIC中断 (8)PWM基础 (9)RCC内部结构与原理 (9)ADC模数转换 (10)内部温度传感器 (10)窗口看门狗 (10)USB应用 (11)三、问题 (11)在线调试 (12)一、入门STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M内核,主要包括STM32F101“基本型”系列、STM32F103“增强型”系列、STM32F105、STM32F107“互联型”系列。
STM32微控制器满足嵌入式开发低功耗和高性能的要求,并且拥有简单易上手的固件函数库,避免了传统ARM单片机开发操作寄存器的模式,所以十分受欢迎,应用广泛。
作者只学过一些51单片机的基础,就直接上手STM32,边学边用。
该篇笔记也是随意的记录一下,要想系统的学习一下,个人认为资料手册(data sheet)、参考手册(Reference Manual)和用户手册(固件函数库)三个文档再有开发板实际操作,完全足够。
熟练掌握以上内容,触类旁通,成为STM32开发的高手指日可待。
目标->实战项目STM32学习方法开发环境(MDK/IAR)→寄存器or固件库→软件仿真&开发板硬件→学习难度建立不受库版本限制的工程项目:1.准备好文件(Startup Code、Lib、User)2.建立工程不添加Startup Code3.工程管理添加需要的库文件、自定义文件4.编译链接ARM简介ARM7衍生出全新的Cortex架构,三管齐下:Cortex-A:高性能应用处理器。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
这是前段时间做彩屏显示时候遇到的难题,
*(__IO uint16_t *) (Bank1_LCD_C)这个就是将后面的数据转换为地址,然后对地址单元存放数据。
可如下等效:
__IO uint16_t *addr;
addr = (__IO uint16_t *) Bank1_LCD_C;
#ifdef和#elif连用,语法和if。
else if语句一样
推挽输出增加驱动,可以驱动LED起来
static int count=0
count++
这个语句中,count仅仅被初始化一次
以后加加一次期中的值就不会变化了
SysTick_CTRL(控制和状态寄存器)
SysTick_LOAD(重装载寄存器)
SysTick_VAL(当前值寄存器)
SysTick_CALIB(校准值寄存器)
TFT经验:弄多大的相片,必须先把那个相片的尺寸改掉,再去取模,才可以,要不会有重影的嘿嘿嘿嘿
VBAT 是电池供电的引脚
VBAT和ADD同时都掉电时才能让备份区复位。
volatile一个变量的存储单元可以在定义该变量的程序之外的某处被引用。
volatile主要是程序员要告诉编译器不要对其定义的这个变量进行优化,防止其不能被引用,不能被改变。
VDDA>2.4V ADC才能工作
VDDA>2.7V USB才能工作
VDD(1.8-3.6v)
VBAT=1.8-3.6v
VSS VSSA VREF必须接到地线
没有外部电源供电时必须VBAT接上VDD
使用PLL时,VDDA必须供电
printf("abs(x)=%d\n",x<0?(-1)*x:x)
条件编译是问号前边为真则取冒号前边的值,为假的,则取后边的值。
所以说上边这条打印的语句是打印x的绝对值。
//stm32f10x_nvic.c
stm32f10x_lib.c
stm32f10x_gpio.c
stm32f10x_flash.c
stm32f10x_rcc.c
TIM6 TIM7基本定时器
(只有这两个定时器不能产生PWM)
TIM1 TIM8高级控制定时器
TIM2 TIM3 TIM4 TIM5为通用定时器
其中高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出。
而通用定时器也能同时产生多达4路的PWM输出,这样,STM32最多可以同时产生30路PWM输出!
修改和自己写代码时候
只是需要修改
main.c
stm3210x_conf.h
stm3210x_it.c
这三个就够了
1:BOOT0接高电平的时候容易自动复位
2:BOOT0接0的时候用户闪存存储器为启动区域
3:BOOT0接1的BOOT1接0的时候用户用系统存储器或内嵌SRAM, 这时候容易自动复位。
4:我的板子是boot0接1,boot1接0,也就是系统存储器为启动区域
使用code这个关键字就能使数据烧写到flash中了
ram类似于电脑中的内存
flash类似硬盘。