模块化编程
1、函数的声明定义写在头文件中,具体实现写在另一个.c
2、main函数想使用哪个模块函数就只需要将头文件引入主程序.c中
3、最后链接的时候会结合在一起
3.8 环境变量
环境变量与文件路径绑定,在linux中可以使用环境变量名代替文件路径
输入env 显示所有环境变量 环境变量=文件路径名(除了代替文件路径还可以代替其他的)
输入 echo $环境变量名 ,查看环境变量的值
系统环境变量:公共的,对全部的用户都生效。
用户环境变量:用户私有的、自定义的个性化设置,只对该用户生效
系统环境变量文件是/etc/profile,用户环境变量文件是etc/.bashrc,一般推荐修改etc/.bashrc
在shell中输入修改环境变量 export ORACLE_HOME=/oracle/home 关掉终端就失效了
3.9 gcc编译
gcc是一个多语言的编译器套件,以gc编译器为核心的编译工具
后面的 -o 是给新文件起一个名字叫做hello.i ,下面是一个预处理后的代码中的一部分
只有编译部分是gcc工作,其他时候都是gcc调用其他的东西执行的
最简单的编译命令,会生成一个a.out的可执行文件
链接器
我们代码不是在一个除了一个.c文件之外,还存在其他.c文件,编译是以.c为单位进行。
当我们某个代码要调用另一个.c文件中的代码的时候,这就需要我们链接器起作用,可以帮我们找到我们需要调用的
库文件
一般就是将一个函数搞进库文件里面,然后我们调用这个库文件就可以直接使用这个函数
一种可以执行、复用代码的二进制形式(本身不可以执行,但是可以被操作系统载入内存中执行)
静态库
简单看成是一组目标文件.o的集合,即很多目标文件经过压缩打包形成的一个文件
链接器从静态库中取得所需的代码就可以,复制到生成可执行文件
动态库
3.9交叉编译工具链的安装
1、将工具链代码移动到/usr/local/arm,然后解压
2、将工具链路径加入/etc/profile,打开/etc/profile 输入export PATH=$PATH:/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin
arm-linux-gnueabihf-gcc -v查看版本
arm-linux-gnueabihf 就是编译链执行的应用程序集合,下面是全部的子程序
3.9 Makefile
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c
clean:
rm *.o
rm main
注意空出来的是使用TAB,不要使用空格。
使用make 就会在当前目标查找Makefile文件,然后运行
main(目标):main.o(依赖) input.o(依赖) calcu.o(依赖)
当依赖不足的时候,就会向下运行查找
使用make clean 就会运行clean:下面的两条指令
变量
$符号表示取变量的值,当变量名多于一个字符时,使用"( )"
$符的其他用法
$^ 表示所有的依赖文件
$@ 表示生成的目标文件
$< 代表第一个依赖文件
注意:所有的自动变量只能出现在命令的位置,不能出现在依赖项和目标中
一个规则
(1)目标的时间必须晚于依赖项的时间,否则目标跟踪
(2)依赖项不存在,找新的规则看有没有产生依赖性的
makefile中第一个对象目标是终极目标,所有要将最终生成的.out放在makefile开头命令
也可以强制指定终极目标ALL关键字
ALL:a.out
两个函数
src = $(wildcard *.c)找到当前目录下所有后缀为.c的文件赋值给src
obj = $(patsubst %.c,%.o,$(src)将src变量中的所有后缀为.c的替换成.o
伪目标.PHONY
伪目标只是一个标签,chean是一个伪目标没有依赖文件,只有用make来调节的时候才会执行
使用伪目标主要是为了避免 Makefile 中定义的执行命令的目标和工作目录下的实际文件出
现名字冲突,有时候我们需要编写一个规则用来执行一些命令
解决办法就是使用伪目标
objects = main.o input.o calcu.o //定义变量
main: $(objects) //规则,用于编译main这个程序。该规则依赖于前面定义的objects变量中的文件
gcc -o main $(objects)
.PHONY : clean //声明一个伪目标
%.o : %.c //规则
gcc -c $< //命令,# 使用gcc编译器编译$<(即第一个依赖项,即.c文件)为.o文件
clean:
rm *.o
rm main
上述规则中并没有创建文件 clean 的命令,因此工作目录下永远都不会存在文件 clean,当
我们输入“make clean”以后,后面的“rm *.o”和“rm main”总是会执行。可是如果我们“手
贱”,在工作目录下创建一个名为“clean”的文件,那就不一样了,当执行“make clean”的时
候,规则因为没有依赖文件,所以目标被认为是最新的,因此后面的 rm 命令也就不会执行,我
们预先设想的清理工程的功能也就无法完成。为了避免这个问题,我们可以将 clean 声明为伪目标
5.14 RAM、ROM、flash、eMMC
RAM:随机存储器,可以读写,断电的时候数据丢失(运行内存)
ROM:只读存储器,不能随意修改,断电的时候数据保存(程序存储器)
ROM掉电数据不丢失,但数据不能随意更新,正是由于该缺点,就有了flash的发展
Flash闪存是属于ROM的一种
EMMc=NAND Flash+闪存控制芯片+标准接口封装
EMM类似于硬盘,将NAND Flash与控制器集成,通过内在的控制器管理Falsh
程序存放在ROM中,运行的时候会江代码搬运到RAM中
单片机与时钟
时钟信号是内部芯片或者外部晶振产生,是单片机的脉搏决定了cpu的频率,时钟信号推动单片机各个部分执行相应的指令。
- STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,也是为了降低整个芯片的耗能。
- 一个机器指令一个时钟周期
STM32本身十分复杂,外设非常多 但我们实际使用的时候只会用到有限的几个外设,使用任何外设都需要时钟才能启动,但并不是所有的外设都需要系统时钟那么高的频率,为了兼容不同速度的设备,有些高速,有些低速,如果都用高速时钟,势必造成浪费 并且,同一个电路,时钟越快功耗越快,同时抗电磁干扰能力也就越弱,所以较为复杂的MCU都是采用多时钟源的方法来解决这些问题。所以便有了STM32的时钟系统和时钟树
通用IO与复用IO
通用IO是指使用GPI0控制引脚的输如输出
复用IO是指使用引脚作为芯片内置外设的功能引脚
一个引脚只能一种复用,不然要使用重映射
通用与复用不能同时存在
5.30 文件挂载
linux系统中的根文件系统数据上层,想要使用下层具体硬盘中的数据资源,需要将硬盘中的空间挂载到linux系统目录中,这样cpu才能通过linux系统根目录去调用硬件资源。
接下来,我们在根目录下新建一个目录 /sdb-u,通过挂载命令将 U 盘文件系统挂载到此目录,挂载效果如图 2 所示。
Linux 系统使用任何硬件设备,都必须将设备文件与已有目录文件进行挂载。
6.6 IO控制
1、时钟开启
2、IO复用(是作用GPIO还是UART的功能引脚之类的)
3、若是复用为GPIO,下一个就是设置GPIO模式(STM32 有八种输入四种,输出四种,linux有些不同但是大概是这样意思)
4、设置GPIO的高低电平(这本质也是对寄存器进行赋值)
6.6 使用visiul studio注意添加头文件
vscode软件设置头文件路径的方法_vscode添加头文件路径-CSDN博客
6.6 ssh,scp 连接
代码学习
#define CCM_CCGR0 *((volatile unsigned int *)0X020C4068)
定义CCM_CCGR0表示0X020C4068地址的值。其中*表示解引用,从地址取到内存。
想要某位置为1,就与1相或,想将某位置为0就与0相并
位置的选择使用左移和右移
与中0,且中1 霸道
GPIO1->GDIR |= (1 << 3); 将GPIO->GDIR 的第四位设置为1
GPIO1->DR &= ~(1 << 3); 将GPIO->GDIR 的第四位设置为0
volatile”进行了修饰,目的是防止编
译器优化。
6.19 git工具的使用
显示出所有的配置文件
git clone config -l
显示系统的配置
git config --system --list
显示用户的配置
git config --global --list
设置用户名和邮箱
git config --global user.name "xxx"
git config --global user.email xxx
每一次提交都会将这个信息上传,如果希望一个项目中使用多个用户名就不用使用global,这样就不设置成全局变量。
6.24 vscode的使用
进入函数之后的回退 ALT +<-
全局搜索 ctrl +shift +F
本文件搜索 ctrl +F
vscode ctrl + p 终端文件搜索
vscode ctrl +y 回退修改
怎么选择多行代码??????
6.27 svn使用
删除文件之后,windows目录下使用svn updata 可以更新文件
删掉的文件,会重新补上。要是想提交新的文件或者删掉一些文件需要使用svn detect ,snv add
svn co +网站 拉取服务器上的代码
svn co http://localhost/test/testapp --username wzhnsc
在当前目录打开show log 可以看到当前目录下所有文件的每一次文件提交的修改
svn set 里面可以切换账号,点击clear
6.28 中断查看
cat /proc/interrupts
第一列:IRQ序号
第二、三列:CPU0/CPU1分别是当前CPU上发生中断的次数
第四列:中断控制器名称,比如IO-APIC
最后一列:设备名称,比如timer
要写一个中断程序,就必须要申请一根中断线,一个中断线又对应一个IRQ号
6.30 软件复位与硬件复位
硬件复位操作寄存器来复位
软件复位
调用一个复位函数进行复位
7.2 extern
extern "C" {
void myFunction(int);
}
通过使用 extern "C"
,你告诉 C++ 编译器不要对括号内的函数或变量进行名称重命名,确保它们能够与 C 代码正确链接。
extern int __init os08a10_init(void);
extern
: 这个关键字表示 os08a10_init
函数是在当前源文件之外定义的。换句话说,这个函数的实现不在当前文件中,而是在其他某个地方(可能是另一个源文件
7.2 _init
和 __exit
int __init os08a10_init(void)
{
int ret;
if (vinc_id > 0xF) { /* multi vin case, use dt ids to load driver automatically */
i2c_driver_os08a10.driver.of_match_table = of_match_ptr(os08a10_dt_ids);
} else {
ret = ambpriv_i2c_update_addr("os08a10", bus_id, addr);
if (ret < 0)
return ret;
}
ret = i2c_add_driver(&i2c_driver_os08a10);
if (ret < 0)
return ret;
return 0;
}
void __exit os08a10_exit(void)
{
i2c_del_driver(&i2c_driver_os08a10);
}
__init
: 这是一个特定于编译器的属性或指令,常见于 Linux 内核编程中。__init
标记告诉编译器和链接器,这个函数是初始化函数,仅在系统启动时调用一次。这意味着,一旦初始化完成,这个函数的代码可以从内核的常驻内存中移除,以节省宝贵的内存资源。在 Linux 内核中,__init
和__exit
是用来标记初始化和清除函数的,它们由内核的初始化机制自动调用
7.2 四种条件编译
1、#if 常量表达式 #endif
#ifdef ABC //要是 ABC被定义了,也就是说这个if是true,就会执行下面的,将代码加入编译
#else
#endif 表示结束
2.多分支的条件编译
#if 常量表达式
#elif 常量表达式
#else
#endif
3.判断是否被定义的条件编译指令
#if defined(symbol)//等价与右边面的写法 #ifdef symbol
#if !defined(symbol)等价右边的写法 #ifndef symbol
4.嵌套指令
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
modos_version_option2();
#endif
#endif
7.4 UART、RS232、RS485
三者本质上都是基于UART,UART 是基于TTL电平传输,但是RS232、RS485 将TTL电平进行转换成其他电平再进行通信传输。
TTL、RS-232、RS-485则是逻辑电平0和1的不同表示标准,它们区别如下
标准 | 逻辑电平0 | 逻辑电平1 | 是否全双工 | 抗干扰能力 |
---|---|---|---|---|
TTL | 输出低电平<0.4V, 输入低电平<=0.8V | 输出高电平>2.4V,输入高电平>=2.0V | 全双工 | 差 |
RS232 | +3~+15V | -3~-15V | 全双工 | 强 |
RS485 | +2V~+6V | - 6V~- 2V | 半双工 | 很强 |
两个设备之间采用RS232通讯
常用的TTL转RS232的电平转换芯片有MAX232,MAX3232。其中MAX232只能用5V供电。而MAX3232可以用5V或3.3V供电。
RS232接口图片如下: