固件库编程
1.初识固件库,关于汇编文件这块视频里讲的很清晰,这里直接放图了
晶振(以下两部分均可以百度)
这里写一下关于晶振的知识,算是基础知识了,以下是我百度的
晶振全名叫晶体振荡器,每个单片机系统里都有晶振,晶振是由石英晶体经过加工并镀上电极而做成的,主要的特性就是通电后会产生机械震荡,可以给单片机提供稳定的时钟源,晶振提供时钟频率越高,单片机的运行速度也就越快。晶振用一种能把电能和机械能相互转化的晶体在共振的状态下工作,以提供稳定,精确的单频振荡。
所以说有了晶振,单片机的定时器才能计时,下面说一下晶振频率和机器周期的换算
时钟周期=晶振周期=1/晶振频率 机器周期=12 * 时钟周期 周期和频率的转换公式应该不用我写吧,就是倒数关系。
晶体频率为12MHZ,则代表1秒振荡12M次,1次耗时1/12us,一个机器周期就是12 * 1/12 = 1us
单片机的最小系统
大致分为三部分:电源部分、晶振部分、复位部分
电源不必多说,得有电源才能工作;
晶振用来产生时钟计时,晶振的作用是(1)为系统提供基本的时钟信号,(2)晶振与锁相环电路配合使用,以提供系统所需的时钟频率;PLL (Phase Locked Loop): 为锁相回路或 锁相环 ,用来统一整合时钟信号,使高频器件正常工作,如内存的存取资料等。 (PLL需要知道一下,别以后见到不知道是什么)
复位,单片机通电需要复位一次。单片机通常有一个低电压复位引脚,即当输入到低电平时,单片机复位。当电阻给电容器充电时,电容器的电压缓慢上升到VCC。当芯片复位脚接近低电平时,芯片复位接近VCC,因此芯片停止复位并完成复位。
2.新建工程
(1)在任意位置新建FWlib-Template
在此文件夹下建四个文件夹
图1
Libraries:用来存放固件库
User:这里的文件是我们自己编写的,其他位置的文件都不是我们自己编写的
Doc:用来放置例程说明,历程的作用,功能,注意事项等,一般是放一个txt文件
最后添加清除垃圾的文件,直接从拷贝
(2)在keil中新建工程,之前写过,这里不再写一遍了,直接将工程放到上述文件的project文件夹下
(3)建好工程以后,将source group1名字改为STARTUP,并在target系新建文件夹和图1一致
右键add Group即可新建文件夹
(4)双击STARTUP向建好的文件夹中添加工程,但是由于(1)中所建文件夹里没有东西,所以先在 (1)中所建文件夹里添加文件,将A盘里的东西复制粘贴过去即可,实际店家给的路径和视频中不太一样,我之前也找了一会,这里直接列出路径A盘(资料盘)\3-STM32官方资料\STM32F103官方固件库与手册(标准库)
Libraries:拷贝这两个文件
删除多余文件:CMSIS里的doc文件,Documentation
startup里的这些文件删除,startup文件路径Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup
将arm里的文件放到startup下,并删除arm文件夹
回到CM3文件下,将CM3/DeviceSupport下的文件剪切到 CMSIS中,并删除DeviceSupport
CM3/CoreSupport也进行同样的操作,并把CM3也删除掉
以上对Libraries的操作在以后的工程里直接拷贝例程里的就好,没必要每一次都弄,只需从以下步骤开始操作
User:建立一个main.c
在main.c写
还有project里的三个文件,A盘(资料盘)\3-STM32官方资料\STM32F103官方固件库与手册(标准库)\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template
project:将固件库template中的这几个文件拷贝到自己建的工程的project里
DOC新建 readme.txt
回到keil下添加文件
srartup里选择hd.s(文件目录:Libraries\CMSIS\startup)只添加hd.s文件
CMSIS里添加CMSIS里的所有.c文件
FWLIB里src里所有文件 ,src路径\Libraries\STM32F10x_StdPeriph_Driver\src
User里添加的也是所有.c文件
DOC
现在编译仍然会出错,这是因为main.c里包含的stm3.h这个头文件现在并没有在我们建好的文件夹下,而是在keil5软件安装目录里,如图,所以我们还要自己指定头文件目录
查看位置方式
头文件所在目录
(5)添加头文件
魔术卡选项,C++里Include Paths里添加所有头文件,并且要指定到具体的那一级目录
需要添加的所有目录
(6)添加conf.h
定义一个宏,添加conf.h的宏和HD容量的宏USE_STDPERIPH_DRIVER,STM32F10x_HD
这样编译后就不会出现问题了
(6)配置
Target里勾选Use MicroLIB选项
Output里勾选creat hex file(hex文件可以通过串口下载)和browse information(不选可能会出现无法跳转发跳转到函数原型的错误)
Output&Listing&debug
关于配置这块,前面已经讲过了,但是老是在这节又讲了一遍,我这里只写了和之前不一样的,有关下载程序错误和解决办法,看笔记二。
MISTAKE
我自己照着笔记操作完第一次编译,报了七十多个警告,这里说一下我的错误
Define输入的时候大小写错误,中间逗号一定要是英文的
还有就是target中的版本一定要选择5
这样编译就不会报错了
GPIO点亮LED灯
将前面建好的工程,另外复制一份,任意改名,我这里改的名字是12-GPIO-LED
User里面添加新文件bsp_led.c和bsp_led.h
bsp_led.c包含头文件,
bsp:板级支持包,和特定板子有关
编译之前别忘记,将bsp_led.h也添加到包含路径里Include Paths
条件编译bsp_led.h,条件编译上一个笔记里写了,这里不再赘述,每写一个头文件都需要条件编译,并在此头文件中包含#include "stm32f10x.h"
然后来到main.c里编写程序,先添加bsp_led.h,在写程序
直接写到main里
int main(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
// 来到这里的时候,系统的时钟已经被配置成72M.
//时钟RCC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
//ODR/BSRR/BSR
//GPIO_SetBits(GPIOB, GPIO_Pin_0);
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
}
但是这里有个问题,如果编译下载程序,灯就不亮,如果是debug一步一步执行,灯就会亮、如果重新上电,就会好
如果你的板子和我是一个情况的话,就不是代码的问题,下载完程序本来就是要复位的,可以上电复位,也可以用指南者自带的复位按键软复位。
但是一般不写道main里,main里写需要实现的功能的函数,具体的实现放到具体的.c文件下,比如这个工程里,上面的代码放到BSP_led.c文件里,mian.c里只写LED_config();和BSR,BSRR寄存器这两行代码就好。
这里放一下最终代码的截图,会清晰一点
我的最终代码和视频里不一样,我觉得这种比较直观,列举一下我犯的错误
这里有两个错,第一个比较简单一眼就能看出来,两个变量写反了
这个的话,keil是不会报错的,但会导致,main里报错,宏定义不需要加;
作业
//bsp:board support package 板级支持包(特定开发板)
#include "BSP_led.h"
void led_G_config(void)
{
GPIO_InitTypeDef GPIO_InitStructG;
// 来到这里的时候,系统的时钟已经被配置成72M.
//时钟RCC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//
GPIO_InitStructG.GPIO_Pin=LED_G;
GPIO_InitStructG.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructG.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructG);
}
void led_B_config(void)
{
GPIO_InitTypeDef GPIO_InitStructB;
// 来到这里的时候,系统的时钟已经被配置成72M.
//时钟RCC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//
GPIO_InitStructB.GPIO_Pin=LED_B;
GPIO_InitStructB.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructB.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructB);
}
void led_R_config(void)
{
GPIO_InitTypeDef GPIO_InitStructR;
// 来到这里的时候,系统的时钟已经被配置成72M.
//时钟RCC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//
GPIO_InitStructR.GPIO_Pin=LED_R;
GPIO_InitStructR.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructR.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructR);
}
GPIO输入
按键是上升沿输入,按键接入管教是PA0,PA0还有wakeup功能,为了统一风格