stm32入门C语言详解
stm32单片机入门c语言解析

stm32 单片机入门c 语言解析
关于学习stm32 单片机建议
推荐学习书籍:
《STM32F103xxx 参考手册》不需要全部阅读没有时间的。
建议选读,但是前几章必读。
存储器和总线架构、电源控制、备份寄存器、复位和时钟控制,通用和复用功能I/O,中断和时间等等前几章一定要花时间阅读。
后面章节,讲述的是具体的功能模块设计。
如果我们用到哪个模块,就可以去阅读哪个模块。
《STM32 固件库使用手册》主要是为了简化编程
学习思路(仅供参考)
步骤一,安装完STM32 学习的软件,比如J-Link、Keil for ARM (MDK)、ISP(如果需要从串口下载的话)。
STM32系列单片机原理及应用——C语言案例教程教学课件U6

广西大学电气工程学院
(接左栏) SDA_OUT(); //SDA 线输出 if(flg){
SDA_SET(); //输出1-NACK }else{
SDA_CLR(); //输出0-ACK } I2C_DELAY(); SCL_SET(); / /SCL置1 I2C_DELAY(); I2C_DELAY(); SCL_CLR(); I2C_DELAY(); SDA_OUT(); //SDA 线输出 //返回读取的数据 return (uint8_t)data; }
个字节传输用于最后一个接收字节的PEC错误校验。 • 兼容SMBus2.0:25ms时钟低超时延时、10ms主设备累积时钟低扩展时间、25ms
从设备累积时钟低扩展时间、带ACK控制的硬件PEC产生/效验、支持地址分辨协议
(ARP) • 兼容SMBus。
第6章 总线通信接口I2C
广西大学电气工程学院
第6章 总线通信接口I2C 6.1.2 I2C工作原理
广西大学电气工程学院
STM32微控制器的I2C模块连接微控制器和I2C总线,提供多主机功能,支持标准和 快速两种传输速率,控制所有I2C总线特定的时序、协议、仲裁和定时。STM32的I2C有 多种用途,包括CRC码的生成和校验、SMBus (系统管理总线)和PMBus(电源管理总 线)。根据特定设备的需要还可以使用DMA以减轻CPU的负担。
1.模式选择,接口可按下述4种模式中的一种运行:
• 从发送器模式。 • 从接收器模式。 • 主发送器模式。 • 主接收器模式。 模块默认工作于从模式:接口在生成起始条件后自动将从模式切换到主模式;当仲 裁丢失或产生停止信号时,则从主模式切换到从模式。允许多主机功能。
2.通信流 主模式时,I2C接口启动数据传输并产生时钟信号。串行数据传输总是以起始条件开始 并以停止条件结束。起始和停止条件都是在主模式下由软件控制产生。 从模式时,I2C 接口能识别它自己的地址(7位或10位)和广播呼叫地址。软件能控制
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系列单片机原理及应用-C语言案例教程 第1章 单片机综述

第1章 单片机综述
其功能主要表现在:
(1)内核:ARM32位Cortex-M3CPU,最高工作频率72MHz, 1.25DMIPS/MHz,单周期乘法和硬件除法
(2)存储器:片上集成32-512KB的Flash存储器。6-64KB的SRAM存储器 (3)时钟、复位和电源管理:2.0-3.6V的电源供电和I/O接口的驱动电压。 POR、PDR和可编程的电压探测器(PVD)。4-16MHz的晶振。内嵌出厂前调校的 8MHz RC振荡电路。内部40 kHz的RC振荡电路,用于CPU时钟的PLL,带校准用 于RTC的32kHz的晶振。 (4)调试模式:串行调试(SWD)和JTAG接口。最多高达112个的快速I/O端口、 11个定时器和13个通信接口 比较流行的器件:STM32F103系列、STM32 L1系列、STM32W系列。
(1)运算器和控制器集成在一个芯片上,称之为CPU芯片。 (2)存储器由半导体存储器芯片组成。 (3)CPU,存储器,I/O 口通过AB,DB,CB三总线交换信息 (4)外设通过I/O口芯片与机器内各部件交换信息。 3.单片机是集成了组成微机的CPU、存储器、I/O口以及其它辅助电路 的大规模集成电路芯片。
3.单片机与嵌入式系统
单片机,就是把中央处理器 CPU、存储器、定时器、I/O 接口电路 等一些计算机的主要功能部件集成在一块集成电路芯片上的微型计算机。 单片机的内部结构如图1.l所示。
时序电路 CPU
总线 控制 逻辑
存储器 I/O
图1.1单片机的内部结构
STM32是一款性价比高的单片机系列。 为高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M内核, 具有高性能外设:1μs的双12位ADC、4MB/s的UART、18MB/s的SPI等
stm32单片机 c语言 技术文章

标题:深入了解STM32单片机C语言编程技术一、介绍STM32单片机STM32单片机是由意法半导体(STMicroelectronics)推出的一款高性能、低功耗的32位微控制器。
其强大的处理能力、丰富的外设接口以及灵活的软件支持,使其成为许多嵌入式系统的首选。
二、C语言在STM32单片机编程中的重要性1. C语言作为常用的嵌入式系统开发语言,具有良好的可移植性和高效性。
在STM32单片机的开发中,广泛应用于程序的编写与调试。
2. 与其他高级语言相比,C语言更接近底层硬件,能够直接操作寄存器、内存等资源,为嵌入式系统的开发提供了更精细的控制。
三、STM32单片机C语言编程的基础知识1. 熟悉单片机的外设及寄存器配置,这是C语言程序与硬件进行通信的基础。
2. 掌握C语言的基本语法与数据类型,如变量的声明与赋值、循环与条件语句等。
3. 理解中断与定时器的概念,掌握在C语言程序中如何处理中断请求和定时器中断。
四、STM32单片机C语言编程的实际应用1. 开发LED控制程序,通过C语言实现LED的闪烁、呼吸灯等效果。
需要了解GPIO口的配置与控制。
2. 实现串口通信,通过C语言编程实现串口数据的发送与接收,实现与PC或其他设备的通信。
3. 编写传感器数据采集程序,通过C语言与ADC、I2C等外设接口交互,获取传感器数据并进行处理。
五、常见问题与解决方法1. 在C语言编程过程中,常常遇到的问题有内存泄露、指针错误、死循环等,需要通过调试工具和技巧进行定位和解决。
2. 外设接口配置不当、寄存器操作错误等也是常见问题,需要仔细查阅资料和手册,深入理解相关硬件原理。
六、总结STM32单片机C语言编程技术是嵌入式系统开发中的重要组成部分,掌握好STM32单片机的基础知识和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--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中C语言知识点初学者必看

STM32中C语言知识点初学者必看1. 数据类型:在C语言中,常用的数据类型包括整型(如int、long)、浮点型(如float、double)、字符型(如char),以及指针类型等。
2.变量和常量:变量是用来存储数据的,而常量是固定的数值,不可修改。
3. 运算符:C语言提供了一系列的运算符,包括算术运算符(如+、-、*、/),关系运算符(如<、>、==、!=),逻辑运算符(如&&,!),位运算符(如&,^),赋值运算符(如=、+=、-=),以及其他一些特殊的运算符(如sizeof、?:)等。
4. 控制语句:C语言提供了若干种控制语句,包括条件语句(如if、switch),循环语句(如for、while、do-while),以及跳转语句(如break、continue、goto)等。
5.数组:数组是一种用于存储相同类型数据的结构,可以通过下标来访问数组中的元素。
6.字符串:字符串是由字符组成的数组,在C语言中,字符串以'\0'结尾。
7.函数:函数是一段具有特定功能的代码块,可以通过函数调用来执行。
C语言中,函数有返回值和无返回值的两种类型。
8.结构体:结构体是一种自定义的数据类型,可以包含多个不同类型的成员变量。
9.指针:指针是用来存储内存地址的变量,可以通过指针来访问和修改内存中的数据。
10.文件操作:C语言提供了一系列的文件操作函数,可以对文件进行读写操作。
11.预处理器:C语言中的预处理器指令以#开头,用于在程序编译之前进行一些预处理操作,如宏定义、条件编译等。
12. 头文件和库:头文件是包含一些函数和变量声明的文件,可以通过#include指令引用。
库文件是包含一些函数和变量实现的文件,可以通过链接库来使用其中的函数和变量。
13. 内存管理:C语言中可以通过动态内存分配函数(如malloc、free)来管理内存的分配和释放。
14. 异常处理:C语言中没有内置的异常处理机制,但可以通过返回错误码或使用setjmp和longjmp来实现简单的异常处理。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
阅读flash:芯片内部存储器flash操作函数我的理解——对芯片内部flash进行操作的函数,包括读取,状态,擦除,写入等等,可以允许程序去操作flash上的数据。
基础应用1,FLASH时序延迟几个周期,等待总线同步操作。
推荐按照单片机系统运行频率,0—24MHz时,取Latency=0;24—48MHz时,取Latency=1;48~72MHz时,取Latency=2。
所有程序中必须的用法:FLASH_SetLatency(FLASH_Latency_2);位置:RCC初始化子函数里面,时钟起振之后。
基础应用2,开启FLASH预读缓冲功能,加速FLASH的读取。
所有程序中必须的用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);位置:RCC初始化子函数里面,时钟起振之后。
3、阅读lib:调试所有外设初始化的函数。
我的理解——不理解,也不需要理解。
只要知道所有外设在调试的时候,EWRAM需要从这个函数里面获得调试所需信息的地址或者指针之类的信息。
基础应用1,只有一个函数debug。
所有程序中必须的。
用法:#ifdef DEBUGdebug();#endif位置:main函数开头,声明变量之后。
4、阅读nvic:系统中断管理。
我的理解——管理系统内部的中断,负责打开和关闭中断。
基础应用1,中断的初始化函数,包括设置中断向量表位置,和开启所需的中断两部分。
所有程序中必须的。
用法:void NVIC_Configuration(void){NVIC_InitTypeDef NVIC_InitStructure; //中断管理恢复默认参数#ifdef VECT_TAB_RAM //如果C/C++ Compiler\Preprocessor\Defined symbols中的定义了VECT_TAB_RAM(见程序库更改内容的表格)NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //则在RAM调试#else //如果没有定义VECT_TAB_RAMNVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//则在Flash里调试#endif //结束判断语句//以下为中断的开启过程,不是所有程序必须的。
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC优先级分组,方式。
//注:一共16个优先级,分为抢占式和响应式。
两种优先级所占的数量由此代码确定,NVIC_PriorityGroup_x可以是0、1、2、3、4,分别代表抢占优先级有1、2、4、8、16个和响应优先级有16、8、4、2、1个。
规定两种优先级的数量后,所有的中断级别必须在其中选择,抢占级别高的会打断其他中断优先执行,而响应级别高的会在其他中断执行完优先执行。
//NVIC_InitStructure.NVIC_IRQChannel = 中断通道名; //开中断,中断名称见函数库//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //启动此通道的中断//NVIC_Init(&NVIC_InitStructure);中断初始化}5、阅读rcc:单片机时钟管理。
我的理解——管理外部、内部和外设的时钟,设置、打开和关闭这些时钟。
基础应用1:时钟的初始化函数过程——用法:void RCC_Configuration(void) //时钟初始化函数{ErrorStatus HSEStartUpStatus; //等待时钟的稳定RCC_DeInit(); //时钟管理重置RCC_HSEConfig(RCC_HSE_ON); //打开外部晶振HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部晶振就绪if (HSEStartUpStatus == SUCCESS){FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//flash读取缓冲,加速FLASH_SetLatency(FLASH_Latency_2); //flash操作的延时RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB使用系统时钟RCC_PCLK2Config(RCC_HCLK_Div2); //APB2(高速)为HCLK的一半RCC_PCLK1Config(RCC_HCLK_Div2); //APB1(低速)为HCLK的一半//注:AHB主要负责外部存储器时钟。
PB2负责AD,I/O,高级TIM,串口1。
APB1负责DA,USB,SPI,I2C,CAN,串口2345,普通TIM。
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MH RCC_PLLCmd(ENABLE); //启动PLLwhile (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}//等待PLL启动RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //将PLL设置为系统时钟源while (RCC_GetSYSCLKSource() != 0x08){}//等待系统时钟源的启动}//RCC_AHBPeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE); //启动AHP设备//RCC_APB2PeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE);//启动ABP2设备//RCC_APB1PeriphClockCmd(ABP2设备1 | ABP2设备2 |, ENABLE); //启动ABP1设备}6、阅读exti:外部设备中断函数我的理解——外部设备通过引脚给出的硬件中断,也可以产生软件中断,19个上升、下降或都触发。
EXTI0~EXTI15连接到管脚,EXTI线16连接到PVD(VDD监视),EXTI线17连接到RTC(闹钟),EXTI线18连接到USB(唤醒)。
基础应用1,设定外部中断初始化函数。
按需求,不是必须代码。
用法:void EXTI_Configuration(void){EXTI_InitTypeDef EXTI_InitStructure; //外部设备中断恢复默认参数EXTI_InitStructure.EXTI_Line = 通道1|通道2; //设定所需产生外部中断的通道,一共19个。
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //产生中断EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //上升下降沿都触发EXTI_InitStructure.EXTI_LineCmd = ENABLE; //启动中断的接收EXTI_Init(&EXTI_InitStructure); //外部设备中断启动}7、阅读dma:通过总线而越过CPU读取外设数据我的理解——通过DMA应用可以加速单片机外设、存储器之间的数据传输,并在传输期间不影响CPU进行其他事情。
这对于入门开发基本功能来说没有太大必要,这个内容先行跳过。
8、阅读systic:系统定时器我的理解——可以输出和利用系统时钟的计数、状态。
基础应用1,精确计时的延时子函数。
推荐使用的代码。
用法:static vu32 TimingDelay; //全局变量声明void SysTick_Config(void) //systick初始化函数{SysTick_CounterCmd(SysTick_Counter_Disable); //停止系统定时器SysTick_ITConfig(DISABLE); //停止systick中断SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //systick使用HCLK作为时钟源,频率值除以8。
SysTick_SetReload(9000); //重置时间1毫秒(以72MHz为基础计算)SysTick_ITConfig(ENABLE); //开启systic中断}void Delay (u32 nTime) //延迟一毫秒的函数{SysTick_CounterCmd(SysTick_Counter_Enable); //systic开始计时TimingDelay = nTime; //计时长度赋值给递减变量while(TimingDelay != 0); //检测是否计时完成SysTick_CounterCmd(SysTick_Counter_Disable); //关闭计数器SysTick_CounterCmd(SysTick_Counter_Clear); //清除计数值}void TimingDelay_Decrement(void) //递减变量函数,函数名由“stm32f10x_it.c”中的中断响应函数定义好了。
{if (TimingDelay != 0x00) //检测计数变量是否达到0{TimingDelay--; //计数变量递减}}注:建议熟练后使用,所涉及知识和设备太多,新手出错的可能性比较大。
新手可用简化的延时函数代替:void Delay(vu32 nCount) //简单延时函数{for(; nCount != 0; nCount--); //循环变量递减计数}当延时较长,又不需要精确计时的时候可以使用嵌套循环:void Delay(vu32 nCount) //简单的长时间延时函数{int i; //声明内部递减变量for(; nCount != 0; nCount--) //递减变量计数{for (i=0; i<0xffff; i++)}//内部循环递减变量计数}9、阅读gpio:I/O设置函数我的理解——所有输入输出管脚模式设置,可以是上下拉、浮空、开漏、模拟、推挽模式,频率特性为2M,10M,50M。