我叫。。。优势。。。。做过啥设计
1.保护定义的变量防止意外的修改,增强程序的健壮性
为什么会被意外的修改呢?有可能时在别的.c文件使用的时候,修改了。
怎么修改,通过指针修改
程序维护,升级的重要性
https://blog.csdn.net/zhanshen112/article/details/80783258
这里的23例题,讲解了static局部变量如何防止被修改。
看到const 的一个反应是它只读。
4
https://blog.csdn.net/silently_frog/article/details/96737764?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522161175906016780255239714%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fall.%252522%25257D&request_id=161175906016780255239714&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29_name-3-96737764.pc_search_result_hbase_insert&utm_term=const+%25E5%2586%2585%25E5%25AD%2598 关于const 内存分配的知识
说明这个变量在别的C文件已经被声明了。
不能重复定义 ,定义只能允许一次!!
被设计用来修饰被不同线程访问和修改的变量
因为不同的线程、硬件,或者操作系统访问的时候是会改变值的
确保指令不会因编译器的优化而省略
既每次都从变量的地址中读取数据
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
存储于进程的全局数据区 (有点类似全局变量)
static 主要是让自己定义的变量,或者函数只能在这个C文件中使用, 你定义的时候不需要考虑别的文件是否由同样的变量,就算有不怕。
1)全局变量的话,一般指的是没有用static所定义的变量,它可以在其它文件被调用,只要在变量前面加上extern就可以了。
2)全局静态变量的话,前面加上static,表示只能在这个文件内使用了,当然了,这也是有好处的,这样不用管其它文件是否定义了相同的变量。即使加了extern 也是不行的
https://baike.baidu.com/item/static/9598919?fr=aladdin#2
static 变量, 静态,因为只能在本文件被调用,所以在程序运行的一开始就被初始化,也是唯一一次初始化
https://blog.csdn.net/zhanshen112/article/details/80783258
这里的23例题,讲解了static局部变量如何防止同文件中其它函数被修改。
i2c总线最多可以挂多少个ic?有哪些因素决定?
1.由IIC地址决定,8位地址,减去1位广播地址,是7位地址,2^7=128,但是地址0x00不用,那就是127个地址, 所以理论上可以挂127个从器件。
2.还受总线电容 400pf的限制,一端测地,一端测线,不能超过400pf
具体看这里 “https://www.firebbs.cn/thread-12702-1-1.html”
推挽输出和开漏输出,两个都是配置输出用的,好像没啥不同,但是确实不一样
开漏出最大不同就是把它置1 的时候,它呈现的是高阻态。
如果需要让它置1的时候也要输出高电平。
怎么办呢?
那就是给个上拉电阻。这个上拉电阻很妙,我们可以让它拉3.3v 也可以让它拉5V。
拉5V就是说要让它输出电平为5V。
为什么有时候要拉5V呢?
因为STM32的IO驱动能力只有3.3V ,而当我们需要连到5V的模块的话,
就得配置为开漏输出,上拉电阻接5V
有什么是5V的模块呢? 多了, 例如有些5V 的lcd1602
第二点比较重要的是它的“线与”特性
通常是用在IIC通信上,(IIC通信上需要把引脚配置为开漏输出)
线与功能有什么用呢?
线与的特性就是当总线上有一个设备输出低电平时,整条总线便处于低电平状态,这时候的总线被称为占用状态。
https://blog.csdn.net/jiangdf/article/details/72779046?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
有常量区, 静态存储区, 代码区, 堆和栈区。
常量区主要是const 的,已经初始化字符串的常量
静态存储区主要是全局变量以及 static的变量
堆区主要是人为申请分配和释放的区
栈区主要是编译器自动分配的,局部变量就放在这
栈比堆快, 系统自动分配,但无法控制
栈比堆快? 不太懂,网上资料较少
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自 由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由 度大。 (经典!)
int a;
int *P
然后 int* p; 这样也可以,测试照常打印, int *p 和 int* p 是一样的
int* p,a; 表示的是定义一个指针变量p,和整形变量a。 而不是说一个p指针和一个a指针
p是指针, 可以存某个变量的地址
例如我要存 a 的地址, 所以 p=&a; (注意这两个数据类型要一致,int型, 否则要强制转换)
然后要打印 a的值的话, 可以这样 :
printf("%d",a);
或者 printf("%d",*p);
这里的*p表示取出指针所指内存地址的值
如果是
printf("%d",p); 这样就变成了打印a 的地址。
char *s;
s="hello";
printf("%s",s); //能够正常打印
char *s;
*s="hello";
printf("%s",s); //不能够正常打印
int a=7;
char *p1;
p1=&a; //!!!这里请注意,char型指针,我指向了int型的
//所以在以下程序中,我赋值必须是整形赋值
scanf("%d",p1);
printf("%d",*p1);
错误示例:
scanf("%s",p1);
printf("%s",*p1);
%s是输入字符串, %c是输入字符,对于 char %x是输入16进制数
如果要定义一个字符串,就是char s[]="hello"; 这样定义可读可写
char *a0 = "hello"; hello 放在常量区 ,只能读写
char a1[]="hello" ; hello 放在栈,可以通过指针去访问和修改数组内容
scanf("%s",a0); // 这样是不允许的,
scanf("%s",a1); //这样是可以的。
#include
#include "windows.h"
void main()
{
char *a;
scanf("%d",&a);
printf("%d",a);
}
这种情况下又是可以的, 但是注意,这里的话是只能输入数字,输入字符的话,结果总是输出1
更新:以上是本人知识薄弱的见解,因为我定义了一个指针,但是没有指向,所以a是野指针。
1.浮空输入在正点代码中用于 触摸按键,以及触摸屏的使用。(正点原子代码)
高阻态是在总线中使用的,例如在那个IIC中,实现线与功能,或者外加上拉电阻接别的模块
浮空输入:对于浮空输入,一直没找到很权威的解释,只好从以下图中去理解了
由于浮空输入一般多用于外部按键输入,结合图上的输入部分电路,我理解为浮空输入状态下,IO的电平状态是不确定的,完全由外部输入决定,如果在该引脚悬空的情况下,读取该端口的电平是不确定的。
3.电路分析时高阻态可做开路理解。你可以把它看作输出(输入)电阻非常大。它的极限状态可以认为悬空(开路)。也就是说理论上高阻态不是悬空,它是对地或对电源电阻极大的状态。而实际应用上与引脚的悬空几乎是一样的。
经过测试, 把STM32串口PA9 PA10脚该为浮空输入是不能运作的
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入功能
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空
然后, PA9 PA10脚改为 复用功能, 然后浮空,是可以运作的
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空
总结,在STM32F4中,模式一定要是复用功能才可以,上下拉浮空的话哪个都行
时序图
SCL线总是为高, SDA线由1到0 开始 SDA线由0到1 结束。
看野火的视频 第24讲 读写EEPROM(第六节-代码讲解-初始化IIC)
在视频中,他给的代码是硬件IIC例程, 其中IO口配置为开漏输出。
其中解释:因为开漏输出逻辑1的时候是高阻态, 这样不会造成短路。
假如是推挽输出,逻辑1的时候高电平, 输出逻辑0的时候低电平,
然后总线上挂载多个模块的时候,会造成短路。
你可能会说,外面上拉电阻不会造成短路吗?不会的,是因为有个电阻嘛,傻
1.硬件上是否无错误,晶振是否起振。2.使用printf函数打印 3.使用assert parrm来 判断参数
4.仿真调试 5.使用示波器来查看引脚信号电平
1.跟同事讨论,讲解一下你处理的流程,2.写文章记录下来(让你在梳理的过程发现错误点)
全局变量和静态变量,生命周期是程序的编译到程序的运行结束为止。 (运行结束可以理解为停下来了,不再执行语句了,或者死机了?)
局部变量的生命周期是程序运行的某一个时刻开始
全局变量没有初始化的话,默认为0
1.加上static
为什么需要malloc? 因为在编程的时候不能确定数组应该定义多大,在程序运行时要根据需要从系统中动态地获取内存空间
不断地申请,如果不释放的话,程序不一定会崩溃
到时候它是返回空指针,也即是不让你去申请了。
当我们使用函数的时候,往往都带有参数,当参数越来越多的时候,如果要增加参数,那么整个函数定义,声明都要改,而使用结构体作为形参,只要增加就可以了,函数的参数时不需要改的。
1.第一种
struct {
member-list; //成员列表,例如人的身高,年龄,性别
} variable-list; //变量列表
这种的话,每次声明变量都要做出一个成员列表这样
2.第二种
struct tag { //带了一个tag
member-list;
}; //取消了变量列表
这种的话,带了一个tag,下次需要声明的时候,直接 struct tag var;
3.第三种
typedef struct{
member-list;
}tag;
这种的话, 连struct 都不需要了, 直接tag var;
在STM32中最常见
结构体指针的话,多数用->
结构体的话,多数用 .作下标
1)就起作用的阶段而言: #define是在编译的预处理阶段起作用,而const是在 编译、运行的时候起作用。
(2)就起作用的方式而言: #define只是简单的字符串替换,没有类型检查。而const有对应的数据类型,是要进行判断的,可以避免一些低级的错误。
(3)就存储方式而言:#define只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若干个备份;const定义的只读变量在程序运行过程中只有一份备份。
(4)从代码调试的方便程度而言: const常量可以进行调试的,define是不能进行调试的,因为在预编译阶段就已经替换掉了。
1.当时我做的两道编程题是 类似字符串的比较 和一个根据按键输入判断密码是否正确。
2.当时抽到的是求一个数的质因子。(算法题)
3.手写一个判断字符串是否对称的函数。
4.给定一个字符串,如何高效地将内部个空格替换成%20
5.strcpy实现原理。
6.翻转单链表
7.完成一个符号数字字母字符串的排序。
51单片机的除了P0脚是开漏输出模式外。
其它IO都是双向IO,
什么是双向IO,就是直接读写,不用配置输入输出模式
。
但是STM32的io口需要配置输入输出模式这样来读写。
但是STM32如何配置双向IO呢,方法是:
将STM32的IO配置成开漏输出,然后外接上拉,就实现了双向IO。
注意:读取IO数据时需要使用GPIO_ReadInputDataBit();
。
char *s;
1.strlen(s)
2.while(*s!='\0')
{
count++;
}
3. for(i=0;t[i]!='\0';i++){
count++;
}
1.有时候我们需要注意操作结构体,以及操作结构体里面的成员变量,这里需要区分,例如结构体指针,但是里面有成员是int类型,所以scanf要取地址,以及另一种我们定义普通结构体,普通结构体里面含有指针变量,free的时候结构体里面的指针变量,不是结构体本身。