第3章-stm32单片机C语言程序设计基础汇总课件

PPT
  • 阅读 95 次
  • 下载 0 次
  • 页数 154 页
  • 大小 1.553 MB
  • 2022-11-12 上传
  • 收藏
  • 违规举报
  • © 版权认领
下载文档40.00 元 加入VIP免费下载
此文档由【小橙橙】提供上传,收益归文档提供者,本网站只提供存储服务。若此文档侵犯了您的版权,欢迎进行违规举报版权认领
第3章-stm32单片机C语言程序设计基础汇总课件
可在后台配置第一页与第二页中间广告代码
第3章-stm32单片机C语言程序设计基础汇总课件
可在后台配置第二页与第三页中间广告代码
第3章-stm32单片机C语言程序设计基础汇总课件
可在后台配置第三页与第四页中间广告代码
第3章-stm32单片机C语言程序设计基础汇总课件
第3章-stm32单片机C语言程序设计基础汇总课件
还剩10页未读,继续阅读
【这是免费文档,您可以免费阅读】
/ 154
  • 收藏
  • 违规举报
  • © 版权认领
下载文档40.00 元 加入VIP免费下载
文本内容

【文档说明】第3章-stm32单片机C语言程序设计基础汇总课件.ppt,共(154)页,1.553 MB,由小橙橙上传

转载请保留链接:https://www.ichengzhen.cn/view-2492.html

以下为本文档部分文字说明:

退出嵌入式单片机原理及应用燕山大学电气工程学院自动化系1ARM嵌入式系统概述2STM32单片机结构和最小系统3基于标准外设库的C语言程序设计基础4STM32通用输入输出GPIO5STM32外部中断6STM32通用定时器7STM32通用同步/异步收发器USART

8直接存储器存取DMA9STM32的模数转换器ADC10STM32的集成电路总线I2C11STM32的串行外设接口SPI第3章基于标准外设库的C语言程序设计基础3.1嵌入式C语言基础文件结构、程序板式、C语言知识精编3.2CMSIS—Cortex-M3微控制器软件接口标准

CMSIS概述、STM32F10x标准外设库3.3基于MDK的STM32开发退出C语言的特点1、语言简单、紧凑、灵活。(32个关键字,9种控制语句)2、运算符丰富(34种表达式)3、数据结构丰富4、具有结构化的控制语句5、目标代码质量高,程序执行效率高。6、可移值性好7、兼有低级语言

和高级语言的特点3.1嵌入式C语言基础3.1嵌入式C语言基础每个C程序通常分为两个文件,一个文件用于保存程序的声明,称为头文件,以“.h”为后缀。另一个文件用于保存程序的实现,称为源文件,以“.c”为后缀。如果一个工程中头文件数目

较多,通常将头文件和源文件分别保存在不同的目录以便于维护。例如可以将头文件保存于inc目录,源文件保存于src目录。退出版权和版本声明/**Copyright(c)2014,燕山大学电气工程学院*Allrightsreserved.*文件名称:filename.h*摘要:简要描述本文件的

内容*当前版本:1.1*作者:输入作者(或修改者)名字*完成日期:2014年7月20日*取代版本:1.0*原作者:输入原作者(或修改者)名字*完成日期:2014年1月10日*/头文件结构头文件版权和版本声明、预处理块和函数声明//版权和版本声明#ifndef__GRAP

HICS_H__#define__GRAPHICS_H__#include<math.h>…#include“myheader.h”//引用非标准库的头文件…voidFunction1(…);//全局函数声明…#e

ndif源文件结构源文件版权和版本声明、头文件的引用和程序的实现体//版权和版本声明#include“graphics.h”…//全局函数的实现体voidFunction1(…){…}…简单的C程序介绍例1:最简单的程序#in

clude<stdio.h>/包含头文件intmain(void)/*主函数*/{printf(“thisisacprogram!\n”);/*输出了一句话*/}例2求两个数之和#include<stdio.h>/包含头文件intm

ain(void)/*主函数*/{inta,b,sum;/*定义变量*/a=100;b=200;/*给变量赋值*/sum=a+b/*求a与b的和*/printf(“sum=%d\n”,sum);/*输出结果*/}scanf(“%d%d”,&a,&b);例3求两个数中的最大数#include<std

io.h>/包含头文件intmax(intx,inty);/*定义max函数,函数值为整型,x,y为型参,整型*/{intz;/*函数内用到内部变量z,也要加以定义*/if(x>y)z=x;/*比较x,y的大小,如果x大于y,则

执行z=x*/elsez=y;/*否则执行z=y*/return(z);/*将z的值返回,通过max带回调用处*/}intmain(void)/*主函数*/{inta,b,c;/*定义变量*/scanf(“%d%d”,&a,&b);/*输入变量a,b的值*/c=

max(a,b);/*调用函数,将得到的值赋给c*/printf(“max=%d\n”,c);/*输出c的值*/}C程序的结构特点和书写格式1、函数是组成C程序的基本结构2、一个函数由两部分组成:函数说

明部分函数体函数体:{[说明部分]执行部分}3、一个程序总是从main函数开始执行4、语句以分号;结束5、书写格式自由6、用/*…*/做注释字符集什么是字符集在C语言程序中允许出现的所有基本字符的组合称为C语言的字符集。字符集分类(1

)大小写英文字母(52个)(2)数字符号(10个)(3)键盘符号(33个)(4)转义字符C语言的基本元素1、符号集(字符集)C语言使用的基本符号共有如下5种:(1)大写字母:A-Z(2)小写字母:a-z(3)阿拉伯数字:0-9(4)下划线:_(5)

标点符号和运算符标识符什么是标识符标识符是用户自定义的一种字符序列,通常用来表示程序中需要辨认的对象名称。标识符的命名规则标识符是由字符或下划线开头的字母、数字、下划线组成的一串符号;保留字不能作为标识符。“_

”可以作为标识符的第一个字母,但是往往用于库代码正确标识符:sumia2a_2_a2_a_2错误的标识符:2aa?c.ga-2ifwhileC语言的数据类型数据是操作的对象,数据类型是指数据的内在表现形式(代码、存储、运算)C语言程序的数据类型如下:空类型数据类型基本类型数据类型指

针类型整型int实型(浮点型)字符型char单精度flaot双精度double数组结构体共用体枚举型派生类型退出关键字意义char声明字符型变量或函数数double声明双精度变量或函数据enum声明枚举类型类float声明浮点型变

量或函数型int声明整型变量或函数long声明长整型变量或函数short声明短整型变量或函数signed声明有符号类型变量或函数struct声明结构体变量或函数union声明共用体(联合)数据类型unsigned声明无符号类型变量或函数void声明函数无返回值或无

参数,声明空类型指针C语言的数据类型常量什么是常量又称为字面量,表述常数常量类型整型常量实型常量字符常量字符串常量常量和变量一、常量和符号常量1、常量:在程序运行过程中,其值不能被改变的量常量区分为不同类型(表现形式)如:12、3.2、‘a’二、变量

1、变量:其值是可以改变的量,它用标识符(变量名)来表示,在内存中占据一定的存储单元。2、变量的定义方法类型符标识符3、注意:1.见字知意2.先定义后使用3.习惯:符号常量大写,变量名小写如:inta,b,max;charc1,c2,s;floatx,y,z;doublei,j;变量变量数

据类型数据类型类型符号占用字节数数据类型类型符号占用字节数整型int4无符号长整型unsignedlong4短整型short2单精度实型float4长整型long4双精度实型double8无符号整型unsignedint4字符型char1无符号短整型unsignedsho

rt2变量存储类型存储类型存储类型符存储地点自动型auto内存堆栈区寄存器型registerCPU的通用寄存器静态型static内存数据区外部参照型extern变量的定义和初始化变量的初始化变量在定义时就要初始化变量赋初值的语句格式[存储

类型符]数据类型符变量名=初值;结构型的定义定义语句struct结构名称{数据类型1成员1名;数据类型2成员2名;..数据类型n成员n名;};结构的本质是不同类型元素的集合结构型变量的定义和引用结构型变量的定义方法:先定义结构型、后定义变量structs

tudent{intid;charname[20];intage;};structstudentx,y;结构型变量成员的引用引用方法结构型变量成员的引用方法引用格式:结构型变量名.成员名结构型变量成员地址的引用方法引用格式:&结构型变量名.成员名结构型变量地址的引用方法引用格

式:&结构型变量名指向结构型数据的指针变量的定义和引用指向结构型变量的指针定义方法:同结构型变量的定义方法,区别在于定义时变量名前面加*。引用方法方法1:(*指针变量).成员名方法2:指针变量->成员名基础练习:输入3个学生

信息,并输出!(使用两种引用方式,结构体变量和结构体指针)学生结构体定义如下:structstudent{intid;charname[20];intage;};编程练习学生管理系统:学生管理系统可以实现学生信息的录入,

查询,注销等功能。定义学生的结构体(以后可以按照具体情况增加个人信息内容)structstudent{intid;charname[20];intage;};C语言中的运算符运算符什么是运算符用来表示各种运算的符号称为运算符。运算符特点运算符必须有运算对象,运算对象都有规定的数据类型

,同时运算结果也有确定的数据类型。每个运算符都有自己特定的运算规则。当表达式中出现多个运算符时则必须考虑运算符的优先级。同级别的运算符还规定了结合性。算术运算符运算符名称优先级结合性+、-取正、取负2自右向左*、/、%乘、除、取余

数3自左向右+、-加、减4自左向右增1、减1运算符有哪些运算符号j=i++;相当于j=I;i=i+1;j=++i;相当于i=i+1;j=i;运算符名称优先级结合性++增12自右向左--减1关系运算符运算符名称优先级结合性>=、>、<=、<大于等于、大于、小于等于、小于6自左向右==、!=等于、

不等于7自左向右关系运算符要点关系运算符可以用来比较两个数值型数据的大小,也可以比较两个字符型数据的大小。关系运算符的运算结果是逻辑值,若为“真”用整数1表示,若为“假”用整数0表示。逻辑运算符运算符名称优先级结合性!逻辑非2自右向左&&逻辑与11自左向右||逻辑或12自左向右逻辑运算符的特点逻

辑运算符运算对象是数值型或字符型等;如果是非0表示逻辑真,0表示逻辑假。运算结果是逻辑值,如运算结果为真用1表示,若为假则用0表示。逻辑运算用“&&”对两个表达式进行计算时,若第1个表达式的值为“假”,则与第2个表达式的值无关,结果肯定为“假”,所以C语言规定此时第2个表达

式不再计算用“||”对两个表达式进行计算时,若第1个表达式的值为“真”,则与第2个表达式的值无关,结果肯定为“真”,所以C语言规定此时第2个表达式不再计算赋值运算符和赋值表达式一、赋值运算符“=”用法:变量=表达式作用:将表达式的值赋给变量如:a=5;ave=(a+

b)/10;二、赋值结果和类型转换1、实型数据(包括单、双精度)赋给整型变量时,舍弃实数的小数部分。2、整型数据赋给单、双精度变量时,数值不变,但以浮点数形式存储到变量中#include“stdio.h”voidmain(){inti;floatf;

i=1.23;f=45;printf(“%d%f\n”,i,f);}结果:i=1f=45.000000逗号运算符和逗号表达式形式:表达式1,表达式2,…表达式n作用:用于连接表达式如:3+5,6-5计算过程:1、求解表达式12、再求解表达式2,…表达式n3、整个逗号

表达式的值是表达式n的值.一个逗号表达式又可以与另一个表达式组成一个新的逗号表达式。如;(a=3*5,a*4),a+5x=a=3,6*a注意:并不是任何地方出现的逗号都是逗号运算符如:printf(“%d,%d\n”,a,b)条件运算符该运算符是三目运算符,其三个运算对象是表达式(e1?

e2:e3);运算规则是如果e1表达式为“真”,取e2表达式的值,否则取e3表达式的值。位运算符什么是位运算是一种对运算对象按二进制位进行操作的运算。位运算的特点位运算不允许只操作其中的某一位,而是对整个数据按二进制位进行运算;位运算的对象只能是整型数据(包括字符型),运

算结果仍是整型数据位运算符分为位逻辑运算符、位移位运算符、位自反赋值运算符三种位运算符运算符名称优先级结合性~位非2自右向左&位与8自左向右^异或9自左向右|位或10自左向右位移位运算符运算符名称优先级结合性<<左移5自左向右>>右移自左向右位运算符按位与&0&0=0;0&

1=0;1&0=0;1&1=1按位或|0|0=0;0|1=1;1|0=1;1|1=1按位异或^0^0=0;0^1=1;1^0=1;1^1=0按位取反~~0=1;~1=0;表达式什么是表达式用运算符将运算对象连接形成的式子就是表达式。

表达式的特点每个表达式都可以按照其中运算符的优先级和运算规则依次对运算对象进行运算,最终获得一个数据,该数据称为表达式的值。表达式值的数据类型就称为表达式的数据类型。表达式的分类主要有六种:算术表达式、关系表达式、逻辑表达式、条件表达式、赋值表达式和逗号表达式。表达式类型转换方法表达式计算中

数据类型的自动转换原则特点:参加运算的各个数据都转换成数据长度最长的数据类型,然后计算。计算结果值当然就是数据长度最长的数据类型例如:设i为int,f为float,d为double,e为long则10+a+i*f-d/e的结果

是double。运算结果存入变量时数据类型的自动转换原则特点:先将运算结果的数据类型自动转换成变量的数据类型,然后再赋予该变量不同类型数据间的混合运算整型、实型(包括单、双精度)、字符型数据间可以混合运算。如:10+’a’+12.3-

4.56*’x’是合法的运算时,不同类型的数据要先转换成同一类型,然后进行运算。转换规则如下:floatdoublelongunsignedintchar,short高低float型数据在运算时一律先转换成double型

不同类型进行混合运算时,按照类型级别由低到高的顺序转换字符型和short型在运算时一律转换成int型分支结构程序设计退出关键字意义for循环语句控do循环语句的循环体制while循环语句的循环条件语break跳出当前循环句continue结束当前循环,开始下一轮循环if条件语

句else条件语句否定分支(与if连用)goto无条件跳转语句switch开关语句case开关语句分支default开关语句中的其它分支return返回语句在C语言中,分支结构主要是利用if语句来实现的,if

语句是对给定的条件进行判断,然后决定执行某个分支。C语言的if语句有3种形式:➢if语句➢ifelse语句➢elseif语句If语句条件执行一般形式为:If(表达式)语句含义:如果表达式的值为真,则执行其后

的语句;否则不执行该语句。语句表达式真(非0)假(0)If(x>0)printf(“hello!”);例:输入两个数,输出其中较大的数main(){inta,b,max;printf(“\ninputtwonumbers:”);scanf(“%d%d”,&a,

&b);max=a;if(max<b)max=b;printf(“max=%d”,max);}if-else语句分支选择一般形式为:if(表达式)语句A;else语句B;含义:如果表达式的值为真,则执行语句A;否则执行语句B.表达式语句A语句B真

(非0)假(0)注意:在C语言中,表达式e的值为非0时,系统均按“真值“处理。如:if(‘a’)printf(“OK”);x=-5;if(x)printf(“OK”);y=0;if(y==0)printf(“OK”);例:输入3个整数,输出最大数最小数

main(){inta,b,c,max,min;printf(“inputthreenumbers:”);scanf(“%d%d%d”,&a,&b,&c);if(a>b){max=a;min=b;}else{max=b;min=a;}if(max<c)max=c;if

(min>c)min=c;printf(“max=%d\tmin=%d\n”,max,min);}else-if语句前面两种形式的if语句一般都用于两个分支情况。在实际程序设计时经常需要进行多分支处理,C语言中进行多分支处理时,可采用else-if语句实现。阶梯式的if语句一般形式if(

表达式1)语句1;elseif(表达式2)语句2;elseif(表达式3)语句3;…elseif(表达式m)语句m;else语句m+1;含义:依次判断各个表达式的值,当出现某个值为真时,则执行其对应的语句,然后跳出else-if结构。如果所有的表达式的值均为假,则执行语句m+1,然后执行后续

程序。表达式1语句1真真真真表达式2表达式3表达式4语句2语句3语句2语句2假假假假例:根据键盘输入字符的类型并输出相应的信息#include<stdio.h>main(){charc;printf("inputacharact

er:");c=getchar();if(c>='0'&&c<='9')printf("Thisisadigit\n");elseif(c>='a'&&c<'z')printf("Thisisasmailletter\n")

;elseif(c>='A'&&c<='Z')printf("Thisisacapitalsmailletter\n");elseprintf("Thisisanothercharacter\n");}i

f语句的嵌套当if语句中的执行语句同时也是if语句时,则构成了if语句嵌套的情形。一般形式:if(表达式)if语句;或者为if(表达式)if语句;elseif语句;在嵌套if语句里特别要注意的是if和else的配对问题。例:比较两个数的大小关系并输出相应的信息main(){inta,b

;printf(“pleaseinputA,B:”);scanf(“%d%d”,&a,&b);if(a!=b)if(a>b)printf(“A>B\n”);elseprintf(“A<B\n”);else

printf(“A=B\n”);}条件运算符如果if语句中,无论表达式的值是“真”还是“假”,均只执行单个的赋值语句,且给同一个变量赋值时,常使用条件表达式来实现。如:if(a>b)max=a;elsem

ax=b;可以采用条件运算符实现:max=(a>b)?a:b;条件运算符是一个3目运算符,即有3个参与运算的量。由条件运算符组成的表达式称为条件表达式:表达式1?表达式2:表达式3使用条件表达式时,还应注意以下几点:(1)条件运算符的运算

优先级低于关系运算符和算术运算符,但高于赋值运算符。(2)条件运算符?和:是一对运算符,不能分开单独使用。(3)条件运算符的结合方向是自右至左。如:a>b?a:c>d?c:d例:比较两个数的大小并输出较大值main(){inta,b;printf(“\ninputtwonumbe

rs:”);scanf(“%d%d”,&a,&b);printf(“max=%d”,a>b?a:b);}switch-case语句在实际中经常需要处理多分支问题,如统计学生成绩分布等,虽然可以用else-if和嵌套if语句来实

现多分支程序设计,但是当分支较多时,程序变得冗长且可读性低。在C语言中提供了直接处理多分支的方法:switch-case语句。一、格式:switch(表达式){case常量表达式1:语句1;case常量表达式2:语句2;…case常量表达式n

:语句n;default:语句n+1;}二、执行过程1.计算表达式的值2.若与常量表达式n值一致,则从该语句开始执行;直到遇到break语句或switch语句的}3、若与任何常量表达式值均不一致时,则执行default语句或执行后续语句其中:表达式可以是整型、字符型、枚举型

常量表达式必须与表达式类型一致(整型与字符型通用)常量表达式中的数据仅起语句标号作用,不作求值判断常量表达式的值必须是唯一的,没有先后顺序多个case语句可以共用一组执行语句循环结构程序设计内容提要:循环就是在满足一定条

件时重复执行一段程序⚫概述⚫构成循环的语句while、do-while、for、if-goto⚫循环结构的比较⚫break语句和continue语句While语句用while语句实现循环while语句的一般形式:while(表达式)语

句;表达式语句下一语句假(0)真(非0)表达式语句当表达式的值为真(非0)时,执行其中的内嵌语句(循环体),然后回过头来再判断表达式的值,如此重复;当表达式为假(0)时结束循环。while语句的一般形式:while(表达式)语句;如:k=1;whi

le(k<=100){s+=k;k++;}循环控制表达式循环控制变量循环体注意:◆若循环体包含一条以上的语句,应以复合语句形式出现◆循环体,必须给循环控制变量赋值◆循环体中,必须有改变循环控制变量值的

语句(使循环趋向结束的语句)◆循环体可以为空如:while((c=getchar())!=‘A’);等价:c=getchar();while(c!=‘A’)c=getchar();编程练习:打印100以内所有的奇数(不包括

100)打印100以内所有的偶数(不包括100)打印100以内所有3的倍数,并统计个数。输入一个数,判断是几位数?(使用循环实现!)do-while循环do-while语句用来实现“直到型”循环,它的一般形式为:do语句While

(表达式);不可以省略切记切记!!!!!!!语句表达式下一语句假真N-S图注意点与while相同for循环for循环的一般形式:for(表达式1;表达式2;表达式3)语句求解表达式1表达式2语句求解表达式3下一

语句假真求解表达式1表达式2语句求解表达式3⚫表达式1在进入循环之前求解(循环变量赋初值)⚫表达式3是循环体的一部分for循环的其他形式:for(;表达式2;)语句表达式3;}表达式1表达式1;表达式3{表达式2为空值永远为真成为死循环变量赋初值这个分号不能移走相当于循环体

的一部分可以移到语句后面来说明1、表达式1省略时,应在for前给循环变量赋初值。如:k=1;for(;k<=3;k++)s+=k;2、表达式2省略时,不判断循环条件,将成为“死循环”,需要在循环体内引入break语句以退出循环3、表达式3省略时,循环体内应有使循环条件

改变的语句如:for(k=1;k<=3;){s+=k;k++;}4、同时省略表达式1和表达式3,只有表达式2,此时相当于while语句。如:k=1;k=1;for(;k<=3;)while(k<=3){s+

=k;k++}{s+=k;k++}5、表达式2一般是关系表达式或逻辑表达式,但也可以是数值表达式或字符表达式,只要其值不等于0就执行循体如:for(k=1;k-4;k++)s+=k;仅当k的值等于4的时候终止循环。k-4是数值表达式。求100以内的奇数、偶数之和循环的嵌套◆一个循环体内包含着另一个

完整的循环结构,就称为循环嵌套◆内嵌的循环中又可以嵌套循环,从而构成多重循环。◆三种循环可以互相嵌套下面给出几种合法的嵌套形式:(1)while嵌套while(2)do-while嵌套do-whilewhile()do{……{……whi

le()do{……}{……}……while();}}while();(3)for嵌套for(4)while嵌套do-whilefor(;;)while(){……{……for(;;)do{……}{……}……while();}……}(5)for嵌套while(6)do-w

hile嵌套forfor(;;)do{……{……while()for{;;}{……}…………}while();}循环嵌套的说明⚫嵌套的循环控制变量不能相同⚫内循环变化快,快循环变化慢⚫正确确定循环体⚫循环控制变量常与求解的问题挂钩有1、2、3、4个数字,能组成多少个互不相

同且无重复数字的三位数?都是多少?main(){inti,j,k;printf("\n");for(i=1;i<5;i++)/*以下为三重循环*/for(j=1;j<5;j++)for(k=1;k<5;k++){if(

i!=k&&i!=j&&j!=k)/*确保i、j、k三位互不相同*/printf("%d,%d,%d\n",i,j,k);}}几种循环的比较一、关于循环的控制循环控制条件修改循环条件循环条件初始化break语句和continue语句一、break语句用break语句可以结束switch结构和三种

循环、for(n=1;n<=100;n++){sum=sum+n;if(sum>1000)break;printf(“%f”,n);}二、continue语句用continue语句可以结束本次循环,既忽略循环体中剩余语句。如

:把100-200之间不能被3整除的数输出本次循环结束循环体的剩余语句被忽略执行表达式3,进下一循环continue总是作if的内嵌语句通用转移语句goto语句Goto语句随意跳转到任意位置Goto语句一般配合标号语句使用Goto语句容易导致代码混乱精心设计的got

o语句可以带来代码的高效Goto语句在嵌入式编程中用的很多3.1.3C语言知识精编关键词退出关键字意义存auto声明自动变量,缺省时一般为“auto”储extern声明变量是在其它文件中声明(也可以看做是引用变量)类register声明寄存器变量型static声明静态变量const声明只读变

量sizeof计算对象所占内存空间大小其typedef给数据类型取别名它volatile说明变量在程序执行中switch开关语句case开关语句分支default开关语句中的其它分支return返回语句3.1.3C语言

知识精编预处理退出预处理命令意义#define宏定义#undef撤销已定义过的宏名#include使编译程序将另一源文件嵌入到带有#include的源文件中#if#if的一般含义是:如果#if后面的常量表达式为true,则编译它与#endi

f之间的代码,否则跳过这些代码。#else#endif标识一个#if块的结束。#elif#else在#if失败的情况下建立另一选择。#endif#elif命令意义与elseif相同,它形成一个ifels

e-if阶梯状语句,可进行多种编译选择。#ifdef#ifndef用#ifdef与#ifndef命令分别表示“如果有定义”及“如果无定义”,是条件编译的另一种方法#line改变当前行数和文件名称,它们是在编译程序中预先定义的标识符,命令的基本形式为:#linenumber["file

name"]#error编译程序时,#error就会生成一个编译错误提示消息,并停止编译#pragma它允许向编译程序传送各种指令,当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。“预处理”是指在对C语言源程序进行编译之前,要先

对程序中的“宏定义、文件包含、条件编译”等特殊命令进行预先处理。宏定义:定义一个标识符来表示一个字符串,称为“宏定义”,该标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”的地方都用字符串去代换。宏定义分类:分为有参数宏定义和无参数宏定义两种。宏的定义不带参数的宏定义

宏定义的一般格式为:#define<标识符>文本串/*#define就是宏定义命令*/功能:将宏名的值定义为指定的文本串。在预处理时凡出现宏名的地方,都用指定的文本串替换。在预处理时将宏名替换成指定的文本串的过程称为“宏展

开”,或称为“宏替换”。【例】求圆周长、面积和相同半径圆球体积。#definePI3.14159voidmain(){floatr,l,s,v;printf(“inputradius:”);scanf(“%f”,&r

);l=2.0*PI*r;s=PI*r*r;v=3.0/4*PI*r*r*r;printf(“l=%6.2f\ns=%6.2f\nv=%6.2f\n”,l,s,v);}程序运行结果:inputradius:6l=37.70s=113.10v=5

08.94注意:(1)宏名为了与变量名区别一般用大写字母表示。(2)宏展开时只用文本串替换宏名,不作正确性检查。(3)宏定义行末尾不能加分号。加分号,宏展时会当作文本串字符一同代入。(4)宏名的有效范围是:从定义位置开始到本文件结

束(5)可以用#undef命令终止宏定义的作用域。(6)在宏定义时,可以引用已定义的宏名。【例】在宏定义时引用已定义的宏名#defineR4.0#definePI3.14159#defineL2*PI*R#defineSPI*R*Rvoidma

in(){printf(“L=%6.2f\nS=%6.2f\n”,L,S);}运行结果如下:L=25.13S=50.27【例】分析下列程序#defineOK100voidmain(){printf("OK");printf("\n

");}运行结果为:OK为什么不是100?带参数的宏定义带参数的宏定义格式如下:#define<宏名>(参数表)文本串功能:定义一个带参数的宏。例如:#defineS(x,y)3*x+2*yarea=S(3,2);宏展开:用实参从左到右逐个字符进行替换文本串中

的形参字符。如图8.1所示。执行:area=S(3,2)宏展开后变成:area=3*3+2*2;【例】求圆的面积。#definePI3.14159#defineS(r)PI*r*rvoidmain(){floata,area;a=3.6;area=S(a);printf

(“area=%6.2f\n”,area);}运行结果:area=40.72说明:(1)宏名与括弧之间不能有空格。(2)宏调用时,实参的个数必须与形参的个数相同。(3)带参数的宏替换时不作语法检查。(4)宏定义时最好在参数两侧加括

号和整个字符串外加括号,防止宏替换出错。【例】分析以下程序运行结果#defineSQ(y)((y)*(y))voidmain(){inta,sq;printf("inputanumber:");scanf("%d",&a);sq=160

/SQ(a+1);printf("sq=%d\n",sq);}比较下面【例6】和【例7】程序的不同之处。【例6】#defineSQ(y)y*yvoidmain(){inta,sq;printf("inputanumber:");scanf("%d",&a);sq=SQ

(a+1);printf("sq=%d\n",sq);}运行结果为:inputanumber:3↙sq=7/*宏代换后得到:sq=a+1*a+1;*/【例7】#defineSQ(y)(y)*(y)voidmain(){inta,sq;pr

intf("inputanumber:")scanf("%d",&a);sq=SQ(a+1);printf("sq=%d\n",sq);}运行结果为:inputanumber:3↙sq=16/*宏代换后得到:sq=(a+1)*(a+1);*/宏调用和函数调用的主要区别:带参宏

函数处理过程不分配内存简单的字符置换分配内存先求实参值,再代入形参处理时间编译时程序运行时参数类型无类型问题定义实参,形参类型程序长度变长不变运行速度不占运行时间调用和返回占时间文件包含:就是将指定文件全部内容包含(

装入)到本文件中来。一般格式:#include“文件名”或#include<文件名>功能:将指定的源文件全部内容包含进来,即装入#include命令所处位置上使其成为一个程序。2文件包含对文件包含命令还要说明以下几点:1.指定文件名可以用双引号或尖括号括起来。例如:#include"

stdio.h"#include<math.h>二者的区别:•用尖括弧时,直接在库函数头文件目录中查找包含文件,称为标准方式;•用双引号时,在用户当前目录中寻找包含的文件,若找不到,再按标准方式查找。一般情况下:包含库函数用尖括弧节

省时间;包含用户自己编写的文件用双引号。2.一个#include命令只能指定一个被包含文件。3.文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。功能:一个源文件可将另一个源文件的内容全部包含进来一般形式:#include“文件名”或#include<文件名>#in

clude“file2.c”file1.cfile2.cfile1.cfile2.cABA处理过程:预编译时,用被包含文件的内容取代该预处理命令,再对“包含”后的文件作一个源文件编译<>直接按标准目录搜索“”先在当前目录搜索,再搜索标准目录可指定路径文件包含源文件(*.c)头文件(*.h)宏定

义数据结构定义函数说明等文件包含可嵌套#include“file2.c”file1.cAfile3.cC#include“file3.c”file2.cBfile1.cAfile3.cfile2.c被包含文件内容/*powers.h*/#definesqr(x)(

(x)*(x))#definecube(x)((x)*(x)*(x))#definequad(x)((x)*(x)*(x)*(x))/*a.c*/#include<stdio.h>#include“powers.h"#defineMAX_POWE

R10voidmain(){intn;printf("number\texp2\texp3\texp4\n");printf("----\t----\t-----\t------\n");for(n=1;n<

=MAX_POWER;n++)printf("%2d\t%3d\t%4d\t%5d\n",n,sqr(n),cube(n),quad(n));}例文件包含举例【例8】给定半径,计算圆的周长和圆的面积。设计三个包含文件,或称为头文件:第1个为:myin1.h#include

<stdio.h>#definePI3.14159第2个为:myin2.hfloatgetlen(floatr){return2*getsr(r)/r;}第3个为:myin3.hfloatgetsr(floatr){return

PI*r*r;}主函数的程序如下:#include“myin1.h”#include“myin3.h”#include“myin2.h”voidmain(){floatx=3.0;printf(“L=%f\n”,getlen(x));printf(“S=%f\n”,getsr(x

));}因为:函数的调用关系,头文件的包含顺序应该必须是:myin1.h,然后myin3.h,最后是myin2.h。一般情况下,对源程序进行全部编译。条件编译:根据具体条件和需要只编译源程序中的某些部分为条件编译。条件编译用途:可以用源程序产生不同版本。3条件编译1.条件编译的三

种形式:形式一:#ifdef标识符程序段1[#else程序段2]#endif功能:标识符已被#define命令定义过则对程序段1进行编译;否则对程序段2进行编译。形式二:#ifndef标识符程序段1#else程序段2#endif功能:如

果标识符未被#define命令定义过则对程序段1进行编译,否则对程序段2进行编译。形式三:#if常量表达式程序段1#else程序段2#endif功能是,如常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。#include<

stdio.h>#defineLETTER0intmain(){charstr[]="Clanguage";charc;inti;for(i=0;str[i]!='\0';i++){c=str[i];#ifLETTERif(c>='a

'&&c<='z')c=c-32;#elseif(c>='A'&&c<='Z')c=c+32;#endifprintf("%c",c);}putchar('\n');return0;}运行结果:CLANGUAGE上

题如果将第一行改为:#defineLETTER0则在预处理时,对第二个IF语句处理,使大写变为小写。目的:掌握宏定义、宏调用,以及宏展的处理过程,掌握文件包含的概念和使用。实训内容:1.试分析以下宏替换后的形式,计算输出结果。要求:先计算运行结果,然后利用程序验证。#include<s

tdio.h>#defineCX(y)2.5+y#definePR(a)printf("%d",(int)(a))#definePR1(a)PR(a);putchar('\n')intmain(void){intx=2;PR1(CX(5)*x);return0;}5练

习2.写出下面程序的运行结果(2)#defineM3#defineNM+1#defineNNN*N/2intmain(){printf(“%d\n”,NN)printf(“%d\n”,5*NN);}(1)#definemin(x,y)x<y?x

:yintmain(){intx=5,y=10,z;z=10*min(x,y);printf(“%d”,z);}1、变量是对程序中数据存储空间(地址和值)的抽象intnum=100;printf(“numis%d,numa

ddris%p\n”,num,&num);2、可以将变量的地址保存在一个整型变量中unsignedintaddr=0;addr=&num;printf(“addris%#x\n”,addr);3、问题是,怎么通过addr简接获取该地址内保存的值(10

0)?变量与地址指针1、C定义了一种专门用于表示地址的变量—指针int*addr;//定义指针变量2、将内存中数据的地址赋值给指针变量:表示将指针指向该数据addr=&num;//指针变量addr指向num变量3、通过指针变量可以间接访问被指向的数据printf(“numis%d\n”,*add

r);//通过addr获取num*addr=200;//通过addr修改numprintf(“numis%d\n”,num);指针的由来用好指针可以:•使程序简洁、紧凑、高效•有效地表示复杂的数据结构•动态分配内存•得到多于一个的函数返回值•直接操作地址造就了C/C++的

强大用不好指针造成:•非法内存访问,程序死机或异常•内存泄露,减低系统性能•指针属于间接访问,指来指去最终变得不可维护指针是把双刃剑指针的定义实例:int*pi;char*pc;double*pd;info_t*pinfo;staticint*pi;staticchar*pc;statici

nfo_t*pinfo;关键概念:1、指针类型与指针指向对象类型2、指针的值与指针指向对象的值指针内存大小指针变量用来表示内存地址,32位CPU上用4byte空间表示地址int*pi;char*pc;double*pd;in

fo_t*pinfo;sizeof(pi)=?sizeof(pc)=?sizeof(pd)=?sizeof(pinfo)=?指针初始化与赋值1、初始化为指向对象的地址intnum=100;intpaddr=&num

;//paddr指向num2、初始化为空指针int*paddr=NULL;//NULL为0,表示空地址3、指针变量定义后可以随时改变所指向的变量intnum1=100,num2=200;int*paddr=NUL

L;paddr=&num1;paddr=&num2;指针运算1、取值运算符intnum=100;int*paddr=&num;通过paddr间接取num值:*paddr2、取址运算符&paddr=?:表示paddr

这个指针变量的地址3、加减运算:偏移指针类型字节数paddr+1=?paddr++?paddr–1=?paddr--?4、强制转换intnum=100;char*paddr=&num;*paddr=?paddr+1=?*(int*)paddr=?(int*)paddr+1=?通用(voi

d)指针指针变量的类型表示指针所指向对象的类型能不能定义一种通用指针,将来根据需要再指向特定对象?void*point=NULL;//void指针,定义不指定指针指向哪种类型数据sizeof(point)=?point++?point--?使用时需要进行强制

类型转换:intnum=100;charch=‘a’;void*point=NULL;point=&num;printf(“numis%d\n”,*(int*)point);point=&ch;printf(“chis%c\n”,*(char*)ch

);数组与指针1、数组与指针的关系⚫数组名表示数组首地址,可以把数组名可作指针常量intarr[3]={1,2,3};int*p=arr;p++?arr++?*p=?*(p+1)=?*(p+2)=?⚫数组下标操作符内部实现机制:通过指针取值运算符实现arr[2]相当于

*(arr+2)⚫数组作为函数参数,实际是转化为指针实现str_cpy(charsrc[],chardes[])=>str_cpy(char*src,char*des)⚫数组作为函数返回值,必须通过指针实现char*str_cpy(char

*src,char*des)数组与指针2、指针数组:即数组的元素为指针类型。char*var[10];//10个int型指针的数组sizeof(var)=?var+1?3、数组指针:即指针的类型为数组(指向数组的指针)。char(*var)[10];//指向10个int型数组的

指针sizeof(var)=?var+1?4、字符串与指针⚫字符串是属于典型的字符数组,因而通常通过char型指针处理字符串数组与指针⚫将字符串直接赋值给指针,表示指针指向字符串内存首地址注意:字符串常量

内存分配在只读数据区(RODATA)实例:char*p=“xnf”;chararr[]={“xnf”};*p?*p++?*++p?*p=‘X’?arr[0]=‘X’?strcpy(p,“XNF”)?strcpy(arr,“XNF”)

?数组与指针⚫通过指针数组表示字符串数组chara[][16]={“welcome”,“to”,“xnf”};主函数参数就是通过指针数组实现的:intmain(intargc,char*argv[])结构与指针1、结构包含指针

:结构体中包含指针域变量如:学生信息中name与phone定义为指针注意:在程序中动态修改学生信息表中的name和phone域可行么?结构与指针2、指向结构体的指针结构体变量域通过.访问,而结构体指针域通过->访问sizeof(info)=?sizeof(p)=?下面这段代

码错在哪里?结构与指针通过结构体指针传递参数比直接传递结构体变量更高效实参传递给形参时只拷贝了4个字节指针与指针1、指向指针变量的指针inti=100;int*p=&i;int**pp=&p;实现指针二级访问:函数与指针1、指针作为函数的参数⚫向函数传递数组、字符串、结构:如str

c_py、show_info⚫作为函数的输出参数例如:实现交换两个整数的函数voidswap(inta,intb)传值,形参值改变并不能带回给实参传址,在函数内改变地址内保存的内容函数与指针问题:要在

函数能改变指针的值,怎么通过输出参数返回?例如:voidget_mem(char*pmem,intsize){pmem=malloc(size);}动态分配的内存能通过pmem带回么?不能!要将实参指针的地址传递给形参(二

级指针)才能实现!更直接的方法是通过函数返回值实现函数与指针2、指针作为函数的返回值返回字符串、动态分配的内存等,如*strcpy,*malloc注意返回地址的有效性(函数执行完毕后该地址未被回收)下面两个函数哪个是合法的?函数与指针3、指向函数的指针函数存放在TEXT段,同样具有地址函数名就

是函数在TEXT段的入口地址跟数组名一样,函数名也可以看作是一个指针常量所以,函数名也可以赋值给指针变量,那么该指针变量类型呢?函数指针类型!通过函数指针,也可以间接调用函数。函数与指针函数指针的应用:1、作为函数参数实现回调函

数所谓回调函数是指通过调用其他函数反过来调用某个函数模拟面向对象的多态,在UI组件的大量使用函数与指针2、作为结构体的动作域模拟面向对象的类,在Linux内核中大量使用作为一个现实中的对象,不但有数据属性,还需要有行为属性使用对象行为3.2Cortex-M3微

控制器软件接口标准什么是CMSIS◆微控制器软件接口标准,即◆(CortexMicrocontrollerSoftwareInterfaceStandard,CMSIS)为什么推出CMSIS◆一个ARM内核会授权给多个厂家,生产种类繁多的产品开发者增加了软件开发成

本◆将所有Cortex芯片厂商产品的软件接口标准化,制定了CMSIS标准。◆芯片厂商就能够将他们的资源专注于产品外设特性的差异化,从而达到降低开发成本的目的。3.2Cortex-M3微控制器软件接口标准应用层代码实时操作系统内核中间件核内外设访

问层中间件访问层设备外设访问层外设寄存器及中断向量定义Cortex处理器系统定时器RTOS内核定时器嵌套中断向量控制器调试/追踪接口其它外设用户应用层操作系统及中间件接口层CMSIS层硬件层CMSIS软件架构3.2Cortex-M3微控制器软件接口标准CMSIS层由三部分构成◆(1

)核内外设访问层(CPAL,CorePeripheralAccessLayer):该层由ARM负责实现。包括对寄存器名称、地址的定义,对核寄存器、NVIC、调试子系统的访问接口定义以及对特殊用途寄存器的访问接口

(例如:CONTROL,xPSR)定义。◆(2)片上外设访问层(DPAL,DevicePeripheralAccessLayer):该层由芯片厂商负责实现。该层的实现与CPAL类似,负责对硬件寄存器地址以及外设访问接口进行定义

。该层可调用CPAL层提供的接口函数同时根据设备特性对异常向量表进行扩展,以处理相应外设的中断请求。◆(3)外设访问函数(AFP,AccessFunctionsforPeripherals):该层也由芯片厂商负责实现,主要是提供访问片上外设的访问函数,这一部分是可选

的。概述◆STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。◆每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API(ap

plicationprogramminginterface应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化。◆ST公司2007年10月发布了V1.0版本的固件库,MDKARM3.22之前的版本均支持该库。2008年6月

发布了V2.0版的固件库,从2008年9月推出的MDKARM3.23版本至今均使用V2.0版本的固件库。V3.0以后的版本相对之前的版本改动较大,本书使用目前较新的V3.4版本。STM32F10x标准外设库概述◆STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件

函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。◆每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API(applicationprogramminginterface应用编程界面)驱动,API对该驱动程序

的结构,函数和参数名称都进行了标准化。◆ST公司2007年10月发布了V1.0版本的固件库,MDKARM3.22之前的版本均支持该库。2008年6月发布了V2.0版的固件库,从2008年9月推出的MD

KARM3.23版本至今均使用V2.0版本的固件库。V3.0以后的版本相对之前的版本改动较大,本书使用目前较新的V3.4版本。STM32F10x标准外设库缩写外设名称缩写外设名称ADC模数转换器I2SIIS总线接口BKP备份寄存器IWDG独立看门狗CAN控制器局域网NVIC嵌套向量中断控制器CR

CCRC计算单元PWR电源控制DAC数模转换器RCC复位和时钟控制DBGMCUMCU调试模块RTC实时时钟DMADMA控制器SDIOSDIO接口EXTI外部中断/事件控制器SPISPI接口SysTick系统定时器FSMC灵活的静态存储器控制器

FlashFlash存储器TIM定时器GPIO通用输入输出USART通用同步异步收发器I2CIIC总线接口WWDG窗口看门狗STM32F10x标准外设库标准外设库中包含了众多的变量定义和功能函数,如果不能了解他们的命名

规范和使用规律将会给编程带来很大的麻烦命名规则◆标准外设库遵从以下命名规则◆PPP表示任一外设缩写,例如:ADC。◆源程序文件和头文件命名都以“stm32f10x_”作为开头,例如:stm32f10x_conf.h。◆常量仅被应用于一

个文件的,定义于该文件中;被应用于多个文件的,在对应头文件中定义。所有常量都由英文字母大写书写。◆寄存器作为常量处理。他们的命名都由英文字母大写书写。在大多数情况下,他们采用与缩写规范一致。◆外设函数的命名以该外设的缩写加下划线为开头。每个单

词的第一个字母都由英文字母大写书写,例如:SPI_SendData。在函数名中,只允许存在一个下划线,用以分隔外设缩写和函数名的其它部分。STM32F10x标准外设库命名规则◆名为PPP_Init的函数,其功能是根据PPP

_InitTypeDef中指定的参数,初始化外设PPP,例如TIM_Init.◆名为PPP_DeInit的函数,其功能为复位外设PPP的所有寄存器至缺省值,例如TIM_DeInit.◆名为PPP_Init的函数,其功能为通过设置PPP_InitTypeDef结构中的各种参数

来定义外设的功能,例如:USART_Init.◆名为PPP_Cmd的函数,其功能为使能或者失能外设PPP,例如:SPI_Cmd.◆名为PPP_ITConfig的函数,其功能为使能或者失能来自外设PPP某中断源,例如:RCC_ITConfig.◆名为

PPP_DMAConfig的函数,其功能为使能或者失能外设PPP的DMA接口,例如:TIM1_DMAConfig.STM32F10x标准外设库命名规则◆用以配置外设功能的函数,总是以字符串“Config”结尾,例如GPIO_PinRemapConfig.◆名为PPP_GetFlagSt

atus的函数,其功能为检查外设PPP某标志位被设置与否,例如:I2C_GetFlagStatus.◆名为PPP_ClearFlag的函数,其功能为清除外设PPP标志位,例如:I2C_ClearFlag.◆名为PPP_GetITStatus的函数,其功能为判断来自外

设PPP的中断发生与否,例如:I2C_GetITStatus.◆名为PPP_ClearITPendingBit的函数,其功能为清除外设PPP中断待处理标志位,例如:I2C_ClearITPendingBi

t.STM32F10x标准外设库库文件结构STM32F10x标准外设库可以从ST的官方网站下载到各种版本的标准外设库,首先看一下3.4版本标准外设库的文件结构,如右图所示。3.0以上版本的文件结构大致相同,每个版本可能略有调整。库文件结构STM32F10x标准外设

库文件功能说明STM32F10x标准外设库文件名功能描述具体功能说明core_cm3.hcore_cm3.cCortex-M3内核及其设备文件访问Cortex-M3内核及其设备:NVIC,SysTick等

访问Cortex-M3的CPU寄存器和内核外设的函数stm32f10x.h微控制器专用头文件这个文件包含了STM32F10x全系列所有外设寄存器的定义(寄存器的基地址和布局)、位定义、中断向量表、存储空间的地址映射等system_stm32f10x.hsystem_stm32f10

x.c微控制器专用系统文件函数SystemInit,用来初始化微控制器函数Sysem_ExtMemCtl,用来配置外部存储器控制器。它位于文件startup_stm32f10x_xx.s/.c,在跳转到main前调用Syste

mFrequncy,该值代表系统时钟频率startup_stm32f10x_Xd.s编译器启动代码微控制器专用的中断处理程序列表(与头文件一致)弱定义(Weak)的中断处理程序默认函数(可以被用户代码覆盖)该文件是与编译器相关的库文件结构STM32F10x标准外设库

文件名功能描述具体功能说明stm32f10x_conf.h固件库配置文件通过更改包含的外设头文件来选择固件库所使用的外设,在新建程序和进行功能变更之前应当首先修改对应的配置。stm32f10x_it.hstm32f10x_it.c外设中断函数文件用户可以

相应的加入自己的中断程序的代码,对于指向同一个中断向量的多个不同中断请求,用户可以通过判断外设的中断标志位来确定准确的中断源,执行相应的中断服务函数。stm32f10x_ppp.hstm32f10x_ppp.c外设驱动函数文件包括了相关外设的初始化配置和部分功能应用函数,这部分是进行编程功能

实现的重要组成部分。Application.c用户文件用户程序文件,通过标准外设库提供的接口进行相应的外设配置和功能设计。3.3基于MDK的STM32开发1.建立工程:在newproject菜单项中点击NewuVisionProject,选择合适路

径,根据应用命名。2.选择芯片型号。3.是否复制启动代码。这里选择否,因为不同版本的启动代码可能不同,后面会把下载好的标准库中的启动代码加到工程中。4.工程管理:新工程文件结构如图3-8所示。创建的工程要有条理性。5工程属性:主要目的是指定相关头文件的路径。右击工程目录

的newproject则会出现Option选项卡。C/C++:需要输入两个非常重要的宏,一个宏是USE_STDPERIPH_DRIVER,定义了这个宏和外设有关的函数才会包括进来,另一个宏是STM32F10X_MD,这个宏指定了CPU的

容量,即中等容量的STM32。除了设定两个宏之外,还要确定和工程有关的头文件的路径。建立工程选择芯片是否复制启动代码新工程文件结构文件管理建立group,添加文件添加文件后工程结构设置输出选项设置C/C++选

小橙橙
小橙橙
文档分享,欢迎浏览!
  • 文档 25747
  • 被下载 7
  • 被收藏 0
相关资源
广告代码123
若发现您的权益受到侵害,请立即联系客服,我们会尽快为您处理。侵权客服QQ:395972555 (支持时间:9:00-21:00) 公众号
Powered by 太赞文库
×
确认删除?