文章目录

  • 一.输入捕获
  • 1.1 输入捕获介绍
  • 1.2 输入捕获框图解析1
  • 1.3 测量频率方法
  • 1.4 异或门
  • 1.5 定时器输入捕获的异或门
  • 1.6 输入捕获框图解析2
  • 1.7 输入捕获通道1更详细的框图
  • 二.输入捕获的基本结构
  • 2.1 输入捕获的基本结构
  • 2.2输入捕获的基本结构代码
  • 三.PWMI基本结构
  • 3.1 结构
  • 3.2 代码
  • 四.输入捕获和输出比较区别
  • 五.两路输出PWM,一路捕获代码
  • 一.输入捕获

    1.1 输入捕获介绍

    下图指定电平跳变是指上升沿和下降沿,可以通过程序配置,发生电平跳变时,输入捕获电路会让当前CNT计数器的值锁存到CCR,锁存CCR的意思就是把当前CNT的值读出来,写入CCR中。

    1.2 输入捕获框图解析1

    (1).4个输入捕获和输出比较通道,共用4个CCR寄存器,CH1-CH4,4个通道和引脚也是共用的,所以对于同一个定时器,输入捕获和输出比较,只能使用其中一个,不能同时使用。

    (2).对于左边的CH1-CH4引脚我们需要把右边的CH1-CH4一 一对应捕获,例如右边的输出比较CH1我们用定时器2,那此时TIM2_CH1被占据,我们就只能用别的定时器的CH1,例如TIM3_CH1,所以我们可以把PA0(TIM2_CH1)接到PA6(TIM3_CH1),左边的CH1-CH4是边沿信号输入引脚,一旦有边沿,比如说上升沿,那么输入滤波和边沿检测电路就会检测到这个上升沿,让输入捕获电路产生动作,这一块作用和外部中断差不多,都是检测电平跳变,然后执行当作,只不过外部中断执行的动作是向CPU申请中断,而这里执行的动作是控制后续电路,让当前CNT的值锁存到CCR寄存器中。

    (3).总结:输出比较是根据CNT和CCR大小关系来执行输出动作,输入捕获是接收到输入信号,执行CNT锁存到CCR的动作。

    (4).输入捕获作用:测量PWM波形的频率,占空比,脉冲间隔,电平持续时间等参数。

    1.3 测量频率方法

    (1).测频法:我们可以设置一个闸门时间T,通常设置1s,在1s时间内,对信号上升沿进行计次,从0开始计,每来一个上升沿计次+1,每来一个上升沿其实就是来了一个周期的信号,所以在1s时间内,来了多少个周期,那它的频率就是多少HZ,一个周期就是低电平和高电平,适合测量高频信号,每1s才可以得到一次结果,所以测频法结果更新比较慢,测量结果是一段时间的平均值,值比较平滑。

    (2).测周法:周期的倒数就是频率,因为T=1/f(f是频率),所以f=1/T(T是周期),如果我们测出一个周期的时间,,周期就是下图红色位置,就可以知道频率是多少,实际上也是定时器计次,我们使用一个已知的标注频率fc的计次时钟,来驱动计数器,从一个上升沿开始计,计数器从0开始,一直计到下一个上升沿,停止计一个数的时间(时钟周期)是T=1/fc,计N个数,N就是CCR,这里的CCR可不是输出比较设置好的CCR,而是在这一个高低电平内,不断自增,到了上升沿或者下降沿,然后把CNT当前的值赋值给CCR,然后每次赋值就会替换掉之前的值,时间就是T=N/fc,然后频率就是时间取倒数,就得到了公式fx=fc/N,这里的fc还需要进行预分频,适合测量低频信号,测周法,只用测量一个周期就能出一次结果,所以出结果的速度取决于待测信号的频率,所以一般情况下,测周法结果更新更快,由于只测一个周期,结果值会受噪声的影响,波动比较大。

    (3).测频法跟测周法计次,这个计次数量N尽量大一些,N越大,相对误差越小,因为在这些方法中计次可能存在正负1误差,比如测频法,并不是每个周期信号都是完整的,比如在最后时间里,可能周期有一个刚刚出现一半,闸门时间就到了,那就只有半个周期,只能舍弃掉或者当一整个周期来看了,因为计次只有整数,不可能计次0.5个数,那在这个过程就会出现多计数一个少计数一个的情况,这就九±1误差,另外测周法也是一样的,要想多减少误差只能多计一点数,当计次N比较大时,正负1对N的影响会很小,比如你去买水,原本2元,商家卖3元,你就会觉得黑心,但是如果是电脑原本5000,卖你5001,你就会觉得无所谓了,当有一个频率,测周法和测频法的计次的N相同,就说明误差不大,这就是中界频率。

    (4).那么高频和低频谁算高,谁算低呢?这就涉及到了中界频率的方法了,中界频率是测周法与测频法误差相等的频率点,公式是怎么算的,就是把测周法和测频法的N提取出来,令两个方法,N相等,把fx解出来,就得到了中界频率了,当待测信号频率<中界频率时,用测周法更适合,当待测信号频率>中界频率时,测频法更适合。

    (5).测频法我们可以用之前写的对射式红外传感器,定时器外部时钟这些代码稍微改进就是测频法,比如对射式红外传感器计次,每来一个上升沿计次就+1,那我们再用定时器定时1s中断,在中断里,每隔1s取一下计次值,同时清0计次,为下一次做准备,这样每次读取的计次值就直接是频率,对应定时器外部时钟的代码也是如此,每隔1s取一下计次,就可以实现测频法测量频率的功能了,我们本文使用的是测周法。

    1.4 异或门

    下图是2个引脚的异或门,3个引脚的异或门:3个引脚电平都相同时输出0,3个引脚电平不相同时输出1。

    1.5 定时器输入捕获的异或门

    下图一位置输入捕获引脚进来,有三输入的异或门,这个异或门的输入接在了通道1,2,3端口,异或门的逻辑是三个引脚的任何一个有电平翻转时,输出引脚就产生一个电平翻转,之后输出通过数据选择器,到达输入捕获通道1,数据选择器如果选择图二的上面位置,那输入捕获通道1的输入,就是3个引脚的异或值,如果选择图三下面位置,那么异或门就没有用,4个通道各用各的引脚,设置这个异或门,其实还是为三相无刷电机服务的,无刷电机有3个霍尔传感器检测转子的位置,可以根据转子的位置进行换相,有了这个异或门,就可以在前3通道接上无刷电机的霍尔传感器,然后这个定时器就作为无刷电机的接口定时器去驱动换相电路工作。

    图一

    图二

    图三

    1.6 输入捕获框图解析2

    (1).然后进行图一的滤波,避免一些高频的毛刺信号误触发,然后边沿检测器跟外部中断一样,可以选择高电平触发或者低电平触发,当出现指定的边沿检测电路时,就会触发后面电路的执行操作,这里其实设置了两套滤波和边沿检测电路,第一套电路,经过滤波和极性选择,得到TI1FP1,输入给通道1给后续电路(图二的红色位置),第二套电路,经过另一个滤波和极性选择,得到TI1FP2,输入给通道2的后续电路(图二的蓝色位置),同理下面的TI2信号进来,也经过两套滤波和极性选择,如图三,所以这里两个通道进来可以各走各的,也可以进行一个交叉,让CH2引脚输入给通道1或者CH1引脚输入给通道2,这么做的目的有两个,第一个是可以灵活切换后续捕获电路的输入,比如你一会想以CH1作为输入,一会想以CH2作为输入,这样就可以通过这个数据寄存器,灵活的进行选择(图四),第二个目的,也是最主要的目的,就是可以把一个引脚的输入,同时映射到两个捕获单元(图五),这也是PWMI结构的经典结构,第一个通道,使用上升沿触发,用来捕获周期,第二个通道用来使用下降沿触发,用来捕获占空比,两个通道对一个引脚进行捕获,就可以同时测量频率和占空比,下面通道3和4也是一样的,但是同时测量占空比和频率时,通道1捕获时,其实占据了通道1和通道2,所以这时候不能使用通道2,通道3和4也是一样的道理,但是这里注意了,只有通道1和通道2有从模式(后期补充看目录1.7的图五),所以用从模式实现硬件清0的话,只能用通道1和通道2,这里stm32f103的输入捕获通道只有通道1和2才能使用,通道3和4无法进行捕获,其他的板子暂时不知道。

    (2).图六的TRC信号来源图六红圈,这个设计也是为了无刷电机。

    (3).之后就来到了预分频器,可以选择对前面的信号进行分频,分频后的触发信号就可以触发捕获电路进行工作了,每来一个触发信号,CNT的值,就会向CCR转运一次,转运的同时会发生一个捕获事件,这个事件会在状态寄存器置标志位,同时也可以产生中断,如果需要在捕获瞬间,处理一些事情的话,就可以开启这个捕获中断,这就是整个电路的流程,比如我们可以设置上升沿触发捕获,每来一个上升沿,CNT转运到CCR一次,又因为这个CNT计数器是由内部标准时钟驱动的,所以CNT的数值,其实就可以来记录两个上升沿之间的时间间隔,这个时间间隔就是周期,在取个倒数,就是测周法的测量频率了。

    (4).这里细节问题就是每次捕获之后,记得把CNT清0一下,这样下次上升沿再一次捕获的时候,取出的才是两个上升沿的时间间隔,要不然就包括了之前的,我们可以用主从触发模式,自动完成。

    图一

    图二

    图三

    图四

    图五

    图六

    1.7 输入捕获通道1更详细的框图

    (1).下图一是框输入捕获内部框图,引脚进来还是先经过一个滤波器,滤波器的输入是TI1,就是CH1引脚,输出的TI1F,就是滤波后的信号,fDTS是滤波器的采样时钟来源,然后CCMR1寄存器里的ICF位可以控制滤波器的参数,如图二,跟上面的滤波器一样(在目录四),越大滤波效果越好,但是信号延迟就越大,滤波后的信号通过边沿检测器,捕获上升沿或者下降沿触发,然后用CCER寄存器里的CC1P位就可以选择极性了,最后得到TI1FP1触发信号,通过数据选择器,进入通道1后续的捕获电路,这里实际上还有一套一样的电路,得到得到TIFP2触发信号,连接通道2的后续电路,这里并没有画出来。
    (2).然后经过数据选择器,进入后续的捕获部分电路,CC1S位可以对数据选择器进行选择,之后ICPS位,可以配置分频器,可以选择不分频,2分频,4分频,8分频,最后CC1E位,控制输出使能或者失能,如果使能了输出,输入端产生指定边沿信号,经过层层电路,就可以让CNT的值,转运到CCR里面来,每一次捕获都要CNT的值清0,以便下一次捕获,在这里硬件电路就可以在捕获之后完成CNT的清0工作,如果自动清0?就是这个TI1FP1信号和TI1的边沿信号都可以通向从模式控制器,这个从模式里面就有自动完成CNT清0,所以可以看出这个从模式就是完成自动化操作的利器。
    (3).主从触发模式有什么用,如何完成硬件自动化的操作?主从触发模式就是主模式,从模式和触发源选择这三个功能的简称,其中主模式可以将定时器的内部信号,映射到TRGO引脚,用于触发别的外设,就叫主模式,从模式就是接收其他外设或者自身外设的一些信号,用于控制自身定时器的运行,也就是被别的信号控制,触发源选择,就是对选择从模式的触发信号源,可以认为是从模式的一部分,触发源选择,选择指定的一个信号,得到TRGI信号,TRGI去触发从模式,从模式可以在列表里面选择一项来自动执行,如果想完成刚刚说的自动清0,那触发源就可以选择TI1FP1,如何从模式执行操作就可以执行图三的RESET操作,这样TI1FP1信号就可以自动清零CNT,实现硬件自动触发。
    (4).如果想实现定时器的级联,如图四,就可以选择定时器主模式输出一个更新信号到TRGO,另一个定时器
    选择上一个定时器触发从模式,从模式选择执行外部时钟模式1的操作,这样就可以实现定时器的级联,我们本文使用的是让CNT清0,就是从模式的复位模式。

    (5).注意:这里输入捕获从模式只有通道1和通道2才支持,也就是从模式那些只有通道1和通道2才可以设置,如图五。

    图一

    图二

    图三

    图四


    图五

    二.输入捕获的基本结构

    2.1 输入捕获的基本结构

    (1).输入捕获的GPIO口输入下图一左上角的方波信号,经过滤波器和边沿检测选择TI1FP1为上升沿为触发,之后选择直连的通道,分频器选择不分频,当TI1FP1出现上升沿之后,CNT的计数值转运到CCR1里(每个时钟周期转运一次),同时触发源选择,选择TI1FP1为触发信号,从模式选择复位,这里有先后顺序,先转运CNT的值到CCR里去,再触发从模式给CNT清零或者是非阻塞的同时转移,CNT的值转移到CCR,同时0转运到CNT里去,总之不会是先清0,再捕获

    (2).下图一中左上角的图,在这里信号会出现一个上升沿,CCR1=CNT,就是把CNT的值转运到CCR1里面去,这是输入捕获自动执行的,然后CNT=0,计数器清零,这是从模式自动执行的,然后在一个周期内,CNT在标准时钟的驱动下,不断自增,并且由于之前清零过了,所以CNT就从上升沿开始,从0开始计数,一直++,一直到下一次上升沿来临,然后执行相同的操作,CCR1=CNT,CNT=0,让CCR1的值始终保持最新一个周期的计数值,如果信号频率太低,CNT的值可能会溢出,我们从模式触发源选择只有通道1和通道2,对于通道3和通道4只有手动清零了。

    (3).当捕获事件发生时,CCR1寄存器会被更新为当前定时器的计数值。这样,你可以通过读取CCR1寄存器的值来获取捕获事件的时间戳。

    图一

    2.2输入捕获的基本结构代码

    main.c

    #include "OLED.h"
    #include "IC.h"
    
    
    uint16_t i;
    
    int main()
    {
    	
    	OLED_Init();
    	PWM_Init();
    	IC_Init();
    	OLED_ShowString(1,1,"Freq:00000HZ");
    
    	OLED_ShowString(3,1,"CNT:");
    	PWM_Setprescaler(72-1);			//Freq=72M/(PSC+1) /100    此时1000hz频率,所以想修改频率就修改这里的PSC就可以了,然后输入捕获的频率fx=fc/N(ARR+1=CRR),fx频率我们从PWM里面计算出来需要的更新频率,然后fc是输入捕获经过预分频之后的频率,N计数器计数的值就是fc/fx=N
    										//比如这里PWM计算1000hz的更新频率,输入捕获预分频系数是72,所以fc=72000000/72=1000000hz,1000000hz/1000hz=1000,所以就对应了下面的1000个数
    	PWM_SetCompare1(50);				//Duty=CCR/100
    	while(1)
    	{
    		OLED_ShowNum(1,6,IC_GetFreq(),5);
    		OLED_ShowNum(3,6,TIM_GetCounter(TIM3),6);//显示输出比较计数器计了几个值
    		
    	}
    }
    
    

    PWM.c

    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    
    	GPIO_InitTypeDef GPIO_InitStrcut;
    	GPIO_InitStrcut.GPIO_Mode=GPIO_Mode_AF_PP;//对于普通的开漏输出/推挽输出,引脚的控制权是来自输出数据寄存器,如果想让定时器来控制引脚,就需要使用复用开漏输出/复用推挽输出
    	GPIO_InitStrcut.GPIO_Pin=GPIO_Pin_0;
    	GPIO_InitStrcut.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStrcut);
    	
    	TIM_InternalClockConfig(TIM2);
    	
    	TIM_TimeBaseInitTypeDef TIM_InitStrcut;
    	TIM_InitStrcut.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_InitStrcut.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_InitStrcut.TIM_Period=100-1;	  //ARR=100-1是分辨率为1%,ARR如果修改会影响到占空比,如果想分辨率为0.1%,那ARR=1000-1
    	TIM_InitStrcut.TIM_Prescaler=720-1;  //PSC预分频器
    	TIM_InitStrcut.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM2,&TIM_InitStrcut);//TIM2_CH1对应TIM_OC1Init
    	
    	
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	TIM_OCStructInit(&TIM_OCInitStruct);//在OCInit初始化函数中有很多参数,通用定时器用不上一些,但是不对这些值赋值的话会时PWM输出出错,所以我们可以用这个函数,它是自动赋值给OCInit函数的所有结构体变量,然后我们下面在修改需要的参数即可
    	//PWM模式1并且是向上计数,CNT<CCR的时候,REF置有效电平(高电平),CNT>=CCR的时候,REF置无效电平(低电平)
    	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式,TIM_OCMode_Timing冻结模式,TIM_OCMode_Active相等时电平置有效电平,TIM_OCMode_Inactive相等时电平置无效电平,TIM_OCMode_Toggle相等时电平翻转,TIM_OCMode_PWM1是PWM模式1,TIM_OCMode_PWM2是PWM模式2
    	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//TIM_OCPolarity_High是高极性,就是极性不翻转,REF波形直接输出,IM_OCPolarity_Low低极性,就是REF电平取反
    	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
    	TIM_OCInitStruct.TIM_Pulse=90;//设置CCR寄存器
    	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
    	
    	TIM_Cmd(TIM2,ENABLE);
    
    }
    
    void PWM_SetCompare1(uint16_t Compare)//设置CCR寄存器的值
    {
    	TIM_SetCompare1(TIM2,Compare);
    }
    
    void PWM_Setprescaler(uint16_t prescaler)//设置PSC预分频器的值
    {
    	TIM_PrescalerConfig(TIM2,prescaler,TIM_PSCReloadMode_Immediate);//这个函数第一个参数是定时器,第二个参数是改变的值,第三是更新事件生效还是立刻生效,TIM_PSCReloadMode_Immediate立刻生效,TIM_PSCReloadMode_Update更新事件生效
    }
    
    

    PWM.h

    #ifndef __PWM_H
    #define __PWM_H
    
    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void);
    void PWM_SetCompare1(uint16_t Compare);
    void PWM_Setprescaler(uint16_t prescaler);
    
    #endif
    
    

    IC.c

    #include "stm32f10x.h"                  // Device header
    
    void IC_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    	GPIO_InitTypeDef GPIO_InitStrcut;
    	GPIO_InitStrcut.GPIO_Mode=GPIO_Mode_IPU;
    	GPIO_InitStrcut.GPIO_Pin=GPIO_Pin_6;
    	GPIO_InitStrcut.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStrcut);
    	
    	TIM_InternalClockConfig(TIM3);
    	TIM_TimeBaseInitTypeDef TIM_TimeInitStruct;
    	TIM_TimeInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_TimeInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_TimeInitStruct.TIM_Period=65536-1;		//ARR  计数器给大一点,防止计数器溢出
    	TIM_TimeInitStruct.TIM_Prescaler=72-1;		//PSC  标准频率=72M/72=1MHZ=1000000hz
    	TIM_TimeInitStruct.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM3,&TIM_TimeInitStruct);
    
    	TIM_ICInitTypeDef TIM_ICInitStruct;
    	TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;//通道1
    	TIM_ICInitStruct.TIM_ICFilter=0x0F;
    	TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;//边沿检测极性选择,上升沿触发,测周期
    	TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
    	TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//数据选择器,TIM_ICSelection_DirectTI直连通道,TIM_ICSelection_IndirectTI交叉通道
    	TIM_ICInit(TIM3,&TIM_ICInitStruct);
    	
    	TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
    	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//硬件清0
    	
    	TIM_Cmd(TIM3,ENABLE);
    }
    
    uint32_t IC_GetFreq(void)//返回最新一个周期的频率值,而不是PWM的更新频率值
    {
    	//单位hz,测周法fx=fc/N,N=CCR+1,TIM_GetCapture1就是返回CCR的值,这里CCR不是输出比较设置好的CCR,而是计数这段高低电平的数量,因为CCR从0开始计数,因此CCR得+1,1000000就是经过预分频之后的频率,经过测试这里会计数1000个数,然后1MHZ/1000=1000hz
    	return 1000000 /(TIM_GetCapture1(TIM3)+1);//单位hz,测周法fx=fc/N,N=CCR+1,TIM_GetCapture1就是返回CCR的值,因为CCR从0开始计数,因此CCR得+1
    }
    
    
    
    

    IC.h

    #ifndef __IC_H
    #define __IC_H
    #include "stm32f10x.h"                  // Device header
    
    void IC_Init(void);
    uint32_t IC_GetFreq(void);
    
    #endif
    
    
    

    OLED.c

    #include "stm32f10x.h"
    #include "OLED_Font.h"
    
    /*引脚配置*/
    #define OLED_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
    #define OLED_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))
    
    /*引脚初始化*/
    void OLED_I2C_Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
     	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
     	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
     	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	
    	OLED_W_SCL(1);
    	OLED_W_SDA(1);
    }
    
    /**
      * @brief  I2C开始
      * @param  无
      * @retval 无
      */
    void OLED_I2C_Start(void)
    {
    	OLED_W_SDA(1);
    	OLED_W_SCL(1);
    	OLED_W_SDA(0);
    	OLED_W_SCL(0);
    }
    
    /**
      * @brief  I2C停止
      * @param  无
      * @retval 无
      */
    void OLED_I2C_Stop(void)
    {
    	OLED_W_SDA(0);
    	OLED_W_SCL(1);
    	OLED_W_SDA(1);
    }
    
    /**
      * @brief  I2C发送一个字节
      * @param  Byte 要发送的一个字节
      * @retval 无
      */
    void OLED_I2C_SendByte(uint8_t Byte)
    {
    	uint8_t i;
    	for (i = 0; i < 8; i++)
    	{
    		OLED_W_SDA(Byte & (0x80 >> i));
    		OLED_W_SCL(1);
    		OLED_W_SCL(0);
    	}
    	OLED_W_SCL(1);	//额外的一个时钟,不处理应答信号
    	OLED_W_SCL(0);
    }
    
    /**
      * @brief  OLED写命令
      * @param  Command 要写入的命令
      * @retval 无
      */
    void OLED_WriteCommand(uint8_t Command)
    {
    	OLED_I2C_Start();
    	OLED_I2C_SendByte(0x78);		//从机地址
    	OLED_I2C_SendByte(0x00);		//写命令
    	OLED_I2C_SendByte(Command); 
    	OLED_I2C_Stop();
    }
    
    /**
      * @brief  OLED写数据
      * @param  Data 要写入的数据
      * @retval 无
      */
    void OLED_WriteData(uint8_t Data)
    {
    	OLED_I2C_Start();
    	OLED_I2C_SendByte(0x78);		//从机地址
    	OLED_I2C_SendByte(0x40);		//写数据
    	OLED_I2C_SendByte(Data);
    	OLED_I2C_Stop();
    }
    
    /**
      * @brief  OLED设置光标位置
      * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
      * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
      * @retval 无
      */
    void OLED_SetCursor(uint8_t Y, uint8_t X)
    {
    	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
    	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
    	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
    }
    
    /**
      * @brief  OLED清屏
      * @param  无
      * @retval 无
      */
    void OLED_Clear(void)
    {  
    	uint8_t i, j;
    	for (j = 0; j < 8; j++)
    	{
    		OLED_SetCursor(j, 0);
    		for(i = 0; i < 128; i++)
    		{
    			OLED_WriteData(0x00);
    		}
    	}
    }
    
    /**
      * @brief  OLED显示一个字符
      * @param  Line 行位置,范围:1~4
      * @param  Column 列位置,范围:1~16
      * @param  Char 要显示的一个字符,范围:ASCII可见字符
      * @retval 无
      */
    void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
    {      	
    	uint8_t i;
    	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
    	for (i = 0; i < 8; i++)
    	{
    		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
    	}
    	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
    	for (i = 0; i < 8; i++)
    	{
    		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
    	}
    }
    
    /**
      * @brief  OLED显示字符串
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  String 要显示的字符串,范围:ASCII可见字符
      * @retval 无
      */
    void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
    {
    	uint8_t i;
    	for (i = 0; String[i] != '\0'; i++)
    	{
    		OLED_ShowChar(Line, Column + i, String[i]);
    	}
    }
    
    /**
      * @brief  OLED次方函数
      * @retval 返回值等于X的Y次方
      */
    uint32_t OLED_Pow(uint32_t X, uint32_t Y)
    {
    	uint32_t Result = 1;
    	while (Y--)
    	{
    		Result *= X;
    	}
    	return Result;
    }
    
    /**
      * @brief  OLED显示数字(十进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~4294967295
      * @param  Length 要显示数字的长度,范围:1~10
      * @retval 无
      */
    void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
    	}
    }
    
    /**
      * @brief  OLED显示数字(十进制,带符号数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:-2147483648~2147483647
      * @param  Length 要显示数字的长度,范围:1~10
      * @retval 无
      */
    void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	uint32_t Number1;
    	if (Number >= 0)
    	{
    		OLED_ShowChar(Line, Column, '+');
    		Number1 = Number;
    	}
    	else
    	{
    		OLED_ShowChar(Line, Column, '-');
    		Number1 = -Number;
    	}
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
    	}
    }
    
    /**
      * @brief  OLED显示数字(十六进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
      * @param  Length 要显示数字的长度,范围:1~8
      * @retval 无
      */
    void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i, SingleNumber;
    	for (i = 0; i < Length; i++)							
    	{
    		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
    		if (SingleNumber < 10)
    		{
    			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
    		}
    		else
    		{
    			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
    		}
    	}
    }
    
    /**
      * @brief  OLED显示数字(二进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
      * @param  Length 要显示数字的长度,范围:1~16
      * @retval 无
      */
    void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
    	}
    }
    
    /**
      * @brief  OLED初始化
      * @param  无
      * @retval 无
      */
    void OLED_Init(void)
    {
    	uint32_t i, j;
    	
    	for (i = 0; i < 1000; i++)			//上电延时
    	{
    		for (j = 0; j < 1000; j++);
    	}
    	
    	OLED_I2C_Init();			//端口初始化
    	
    	OLED_WriteCommand(0xAE);	//关闭显示
    	
    	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
    	OLED_WriteCommand(0x80);
    	
    	OLED_WriteCommand(0xA8);	//设置多路复用率
    	OLED_WriteCommand(0x3F);
    	
    	OLED_WriteCommand(0xD3);	//设置显示偏移
    	OLED_WriteCommand(0x00);
    	
    	OLED_WriteCommand(0x40);	//设置显示开始行
    	
    	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常 0xA0左右反置
    	
    	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常 0xC0上下反置
    
    	OLED_WriteCommand(0xDA);	//设置COM引脚硬件配置
    	OLED_WriteCommand(0x12);
    	
    	OLED_WriteCommand(0x81);	//设置对比度控制
    	OLED_WriteCommand(0xCF);
    
    	OLED_WriteCommand(0xD9);	//设置预充电周期
    	OLED_WriteCommand(0xF1);
    
    	OLED_WriteCommand(0xDB);	//设置VCOMH取消选择级别
    	OLED_WriteCommand(0x30);
    
    	OLED_WriteCommand(0xA4);	//设置整个显示打开/关闭
    
    	OLED_WriteCommand(0xA6);	//设置正常/倒转显示
    
    	OLED_WriteCommand(0x8D);	//设置充电泵
    	OLED_WriteCommand(0x14);
    
    	OLED_WriteCommand(0xAF);	//开启显示
    		
    	OLED_Clear();				//OLED清屏
    }
    
    

    OLED.h

    #ifndef __OLED_H
    #define __OLED_H
    
    #include "stm32f10x.h"                  // Device header
    
    
    void OLED_Init(void);
    void OLED_Clear(void);
    void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
    void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
    void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
    void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    
    #endif
    
    

    OLED_Font.h

    #ifndef __OLED_FONT_H
    #define __OLED_FONT_H
    
    #include "stm32f10x.h"                  // Device header
    
    
    /*OLED字模库,宽8像素,高16像素*/
    const uint8_t OLED_F8x16[][16]=
    {
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//  0
    	
    	0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
    	
    	0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
    	
    	0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
    	0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
    	
    	0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
    	0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
    	
    	0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
    	0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
    	
    	0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
    	0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
    	
    	0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
    	
    	0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
    	0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
    	
    	0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
    	0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
    	
    	0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
    	0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
    	
    	0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
    	0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
    	
    	0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
    	0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
    	
    	0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
    	0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
    	
    	0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
    	
    	0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
    	0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
    	
    	0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
    	0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
    	
    	0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
    	0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
    	
    	0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
    	0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
    	
    	0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
    	0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
    	
    	0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
    	0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
    	
    	0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
    	0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
    	
    	0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
    	0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
    	
    	0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
    	
    	0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
    	
    	0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
    	0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
    	
    	0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
    	0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
    	
    	0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
    	0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
    	
    	0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
    	0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
    	
    	0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
    	0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
    	
    	0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
    	0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
    	
    	0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
    	
    	0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
    	0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
    	
    	0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
    	
    	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
    	0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
    	
    	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
    	0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
    	
    	0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
    	0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
    	
    	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
    	0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
    	
    	0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
    	
    	0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
    	0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
    	
    	0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
    	0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
    	
    	0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
    	
    	0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
    	0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
    	
    	0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
    	0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
    	
    	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
    	
    	0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
    	0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
    	
    	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
    	
    	0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
    	0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
    	
    	0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
    	0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
    	
    	0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
    	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
    	
    	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
    	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
    	
    	0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
    	0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
    	
    	0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
    	0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
    	
    	0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
    	0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
    	
    	0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
    	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
    	
    	0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
    	0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
    	
    	0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
    	0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
    	
    	0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
    	
    	0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
    	0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
    	
    	0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
    	
    	0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
    	
    	0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
    	0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
    	
    	0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
    	
    	0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
    	
    	0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
    	
    	0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
    	
    	0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
    	
    	0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
    	0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
    	
    	0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
    	0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
    	
    	0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
    	
    	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
    	
    	0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
    	
    	0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
    	0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
    	
    	0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
    	
    	0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
    	0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
    	
    	0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
    	0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
    	
    	0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
    	0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
    	
    	0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
    	0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
    	
    	0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
    	0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
    	
    	0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
    	0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
    	
    	0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
    	0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
    	
    	0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
    	
    	0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
    	0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
    	
    	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
    	
    	0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
    	0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
    	
    	0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
    };
    
    #endif
    
    

    三.PWMI基本结构

    3.1 结构

    (1).这里PWMI模式,使用了两个通道同时捕获一个引脚,就是可以把一个引脚的输入,同时映射到两个捕获单元,这也是PWMI结构的经典结构,第一个通道,使用上升沿触发,用来捕获周期,第二个通道用来使用下降沿触发,用来捕获占空比,两个通道对一个引脚进行捕获,就可以同时测量频率和占空比。
    (2).最开始上升沿,CCR1捕获,同时清零CNT,之后CNT一直++,然后在下降沿这个时刻,触发CCR2捕获,所以这时CCR2的值就是CNT从上升沿计到下降沿的值,就是高电平期间的计数值,CCR2捕获并不触发CNT清零,所以CNT继续++,直到下一次上升沿,CCR1捕获周期,CNT清零,这样执行以后,CCR1就是一整个周期的计数值,CCR2就是高电平期间的计数值,我们用CCR2/CCR1,就是占空比了,这就是PWMI模式,使用两个通道来捕获频率和占空比的思路。

    3.2 代码

    main.c

    include "stm32f10x.h"  // Device header
    #include "PWM.h"
    #include "OLED.h"
    #include "IC.h"
    
    
    uint16_t i;
    
    int main()
    {
    	
    	OLED_Init();
    	PWM_Init();
    	IC_Init();
    	OLED_ShowString(1,1,"Freq:00000HZ");
    	OLED_ShowString(2,1,"Duty:00%");
    
    	OLED_ShowString(3,1,"CNT:");
    	OLED_ShowString(4,1,"PSC:");
    	PWM_Setprescaler(720-1);			//Freq=72M/(PSC+1) /100    此时1000hz频率,所以想修改频率就修改这里的PSC就可以了,然后输入捕获的频率fx=fc/N(ARR+1=CRR),fx频率我们从PWM里面计算出来需要的更新频率,然后fc是输入捕获经过预分频之后的频率,N计数器计数的值就是fc/fx=N
    										//比如这里PWM计算1000hz的更新频率,输入捕获预分频系数是72,所以fc=72000000/72=1000000hz,1000000hz/1000hz=1000,所以就对应了下面的1000个数
    	PWM_SetCompare1(50);				//Duty=CCR/100
    	while(1)
    	{
    		OLED_ShowNum(1,6,IC_GetFreq(),5);
    		OLED_ShowNum(2,6,IC_GetDuty(),2);
    		OLED_ShowNum(3,6,TIM_GetCounter(TIM3)+1,6);//显示输出比较计数器计了几个值
    		OLED_ShowNum(4,6,TIM_GetCapture1(TIM3)+1,6);
    	}
    }
    
    
    
    

    PWM.c

    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    
    	GPIO_InitTypeDef GPIO_InitStrcut;
    	GPIO_InitStrcut.GPIO_Mode=GPIO_Mode_AF_PP;//对于普通的开漏输出/推挽输出,引脚的控制权是来自输出数据寄存器,如果想让定时器来控制引脚,就需要使用复用开漏输出/复用推挽输出
    	GPIO_InitStrcut.GPIO_Pin=GPIO_Pin_0;
    	GPIO_InitStrcut.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStrcut);
    	
    	TIM_InternalClockConfig(TIM2);
    	
    	TIM_TimeBaseInitTypeDef TIM_InitStrcut;
    	TIM_InitStrcut.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_InitStrcut.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_InitStrcut.TIM_Period=100-1;	  //ARR=100-1是分辨率为1%,ARR如果修改会影响到占空比,如果想分辨率为0.1%,那ARR=1000-1
    	TIM_InitStrcut.TIM_Prescaler=720-1;  //PSC预分频器
    	TIM_InitStrcut.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM2,&TIM_InitStrcut);//TIM2_CH1对应TIM_OC1Init
    	
    	
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	TIM_OCStructInit(&TIM_OCInitStruct);//在OCInit初始化函数中有很多参数,通用定时器用不上一些,但是不对这些值赋值的话会时PWM输出出错,所以我们可以用这个函数,它是自动赋值给OCInit函数的所有结构体变量,然后我们下面在修改需要的参数即可
    	//PWM模式1并且是向上计数,CNT<CCR的时候,REF置有效电平(高电平),CNT>=CCR的时候,REF置无效电平(低电平)
    	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式,TIM_OCMode_Timing冻结模式,TIM_OCMode_Active相等时电平置有效电平,TIM_OCMode_Inactive相等时电平置无效电平,TIM_OCMode_Toggle相等时电平翻转,TIM_OCMode_PWM1是PWM模式1,TIM_OCMode_PWM2是PWM模式2
    	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//TIM_OCPolarity_High是高极性,就是极性不翻转,REF波形直接输出,IM_OCPolarity_Low低极性,就是REF电平取反
    	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
    	TIM_OCInitStruct.TIM_Pulse=90;//设置CCR寄存器
    	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
    	
    	TIM_Cmd(TIM2,ENABLE);
    
    }
    
    void PWM_SetCompare1(uint16_t Compare)//设置CCR寄存器的值
    {
    	TIM_SetCompare1(TIM2,Compare);
    }
    
    void PWM_Setprescaler(uint16_t prescaler)//设置PSC预分频器的值
    {
    	TIM_PrescalerConfig(TIM2,prescaler,TIM_PSCReloadMode_Immediate);//这个函数第一个参数是定时器,第二个参数是改变的值,第三是更新事件生效还是立刻生效,TIM_PSCReloadMode_Immediate立刻生效,TIM_PSCReloadMode_Update更新事件生效
    }
    
    

    PWM.h

    #ifndef __PWM_H
    #define __PWM_H
    
    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void);
    void PWM_SetCompare1(uint16_t Compare);
    void PWM_Setprescaler(uint16_t prescaler);
    
    #endif
    
    

    IC.c

    #include "stm32f10x.h"                  // Device header
    
    void IC_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    	GPIO_InitTypeDef GPIO_InitStrcut;
    	GPIO_InitStrcut.GPIO_Mode=GPIO_Mode_IPU;
    	GPIO_InitStrcut.GPIO_Pin=GPIO_Pin_6;
    	GPIO_InitStrcut.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStrcut);
    	
    	TIM_InternalClockConfig(TIM3);
    	TIM_TimeBaseInitTypeDef TIM_TimeInitStruct;
    	TIM_TimeInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_TimeInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_TimeInitStruct.TIM_Period=65536-1;		//ARR  计数器给大一点,防止计数器溢出
    	TIM_TimeInitStruct.TIM_Prescaler=72-1;		//PSC  标准频率=72M/72=1MHZ=1000000hz
    	TIM_TimeInitStruct.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM3,&TIM_TimeInitStruct);
    
    	TIM_ICInitTypeDef TIM_ICInitStruct;
    	TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;//通道1
    	TIM_ICInitStruct.TIM_ICFilter=0x0F;
    	TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;//边沿检测极性选择,上升沿触发,测周期
    	TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
    	TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//数据选择器,TIM_ICSelection_DirectTI直连通道,TIM_ICSelection_IndirectTI交叉通道
    	TIM_ICInit(TIM3,&TIM_ICInitStruct);
    	
    	TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);//会自动把剩下的一个通道初始化成相反的配置,这里传入通道1直连,上升沿,那就会自动配置通道2交叉,下降沿,这个函数只支持通道1和2的配置
    //	TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;//通道2
    //	TIM_ICInitStruct.TIM_ICFilter=0x0F;
    //	TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Falling;//边沿检测极性选择,下降沿触发,测占空比
    //	TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
    //	TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_IndirectTI;//数据选择器,TIM_ICSelection_DirectTI直连通道,TIM_ICSelection_IndirectTI交叉通道
    //	TIM_ICInit(TIM3,&TIM_ICInitStruct);
    	
    	TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
    	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//硬件清0
    	
    	TIM_Cmd(TIM3,ENABLE);
    }
    
    uint32_t IC_GetFreq(void)//返回最新一个周期的频率值,而不是PWM的更新频率值
    {
    	//单位hz,测周法fx=fc/N,N=CCR+1,TIM_GetCapture1就是返回CCR的值,这里CCR不是输出比较设置好的CCR,而是计数这段高低电平的数量,因为CCR从0开始计数,因此CCR得+1,1000000就是经过预分频之后的频率,经过测试这里会计数1000个数,然后1MHZ/1000=1000hz
    	return 1000000 /(TIM_GetCapture1(TIM3)+1);
    }
    
    uint32_t IC_GetDuty(void)//占空比,这里只是负责返回,设置占空比不在这里设置
    {
    	return (TIM_GetCapture2(TIM3) + 1)*100 /(TIM_GetCapture1(TIM3) + 1);//CCR2+1/CCR1+1,乘100是让他以百分比的形式出现
    }
    
    
    
    
    

    IC.h

    #ifndef __IC_H
    #define __IC_H
    #include "stm32f10x.h"                  // Device header
    
    void IC_Init(void);
    uint32_t IC_GetFreq(void);
    uint32_t IC_GetDuty(void);
    	
    #endif
    
    
    
    

    OLED.c

    #include "stm32f10x.h"
    #include "OLED_Font.h"
    
    /*引脚配置*/
    #define OLED_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
    #define OLED_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))
    
    /*引脚初始化*/
    void OLED_I2C_Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
     	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
     	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
     	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	
    	OLED_W_SCL(1);
    	OLED_W_SDA(1);
    }
    
    /**
      * @brief  I2C开始
      * @param  无
      * @retval 无
      */
    void OLED_I2C_Start(void)
    {
    	OLED_W_SDA(1);
    	OLED_W_SCL(1);
    	OLED_W_SDA(0);
    	OLED_W_SCL(0);
    }
    
    /**
      * @brief  I2C停止
      * @param  无
      * @retval 无
      */
    void OLED_I2C_Stop(void)
    {
    	OLED_W_SDA(0);
    	OLED_W_SCL(1);
    	OLED_W_SDA(1);
    }
    
    /**
      * @brief  I2C发送一个字节
      * @param  Byte 要发送的一个字节
      * @retval 无
      */
    void OLED_I2C_SendByte(uint8_t Byte)
    {
    	uint8_t i;
    	for (i = 0; i < 8; i++)
    	{
    		OLED_W_SDA(Byte & (0x80 >> i));
    		OLED_W_SCL(1);
    		OLED_W_SCL(0);
    	}
    	OLED_W_SCL(1);	//额外的一个时钟,不处理应答信号
    	OLED_W_SCL(0);
    }
    
    /**
      * @brief  OLED写命令
      * @param  Command 要写入的命令
      * @retval 无
      */
    void OLED_WriteCommand(uint8_t Command)
    {
    	OLED_I2C_Start();
    	OLED_I2C_SendByte(0x78);		//从机地址
    	OLED_I2C_SendByte(0x00);		//写命令
    	OLED_I2C_SendByte(Command); 
    	OLED_I2C_Stop();
    }
    
    /**
      * @brief  OLED写数据
      * @param  Data 要写入的数据
      * @retval 无
      */
    void OLED_WriteData(uint8_t Data)
    {
    	OLED_I2C_Start();
    	OLED_I2C_SendByte(0x78);		//从机地址
    	OLED_I2C_SendByte(0x40);		//写数据
    	OLED_I2C_SendByte(Data);
    	OLED_I2C_Stop();
    }
    
    /**
      * @brief  OLED设置光标位置
      * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
      * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
      * @retval 无
      */
    void OLED_SetCursor(uint8_t Y, uint8_t X)
    {
    	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
    	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
    	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
    }
    
    /**
      * @brief  OLED清屏
      * @param  无
      * @retval 无
      */
    void OLED_Clear(void)
    {  
    	uint8_t i, j;
    	for (j = 0; j < 8; j++)
    	{
    		OLED_SetCursor(j, 0);
    		for(i = 0; i < 128; i++)
    		{
    			OLED_WriteData(0x00);
    		}
    	}
    }
    
    /**
      * @brief  OLED显示一个字符
      * @param  Line 行位置,范围:1~4
      * @param  Column 列位置,范围:1~16
      * @param  Char 要显示的一个字符,范围:ASCII可见字符
      * @retval 无
      */
    void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
    {      	
    	uint8_t i;
    	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
    	for (i = 0; i < 8; i++)
    	{
    		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
    	}
    	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
    	for (i = 0; i < 8; i++)
    	{
    		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
    	}
    }
    
    /**
      * @brief  OLED显示字符串
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  String 要显示的字符串,范围:ASCII可见字符
      * @retval 无
      */
    void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
    {
    	uint8_t i;
    	for (i = 0; String[i] != '\0'; i++)
    	{
    		OLED_ShowChar(Line, Column + i, String[i]);
    	}
    }
    
    /**
      * @brief  OLED次方函数
      * @retval 返回值等于X的Y次方
      */
    uint32_t OLED_Pow(uint32_t X, uint32_t Y)
    {
    	uint32_t Result = 1;
    	while (Y--)
    	{
    		Result *= X;
    	}
    	return Result;
    }
    
    /**
      * @brief  OLED显示数字(十进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~4294967295
      * @param  Length 要显示数字的长度,范围:1~10
      * @retval 无
      */
    void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
    	}
    }
    
    /**
      * @brief  OLED显示数字(十进制,带符号数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:-2147483648~2147483647
      * @param  Length 要显示数字的长度,范围:1~10
      * @retval 无
      */
    void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	uint32_t Number1;
    	if (Number >= 0)
    	{
    		OLED_ShowChar(Line, Column, '+');
    		Number1 = Number;
    	}
    	else
    	{
    		OLED_ShowChar(Line, Column, '-');
    		Number1 = -Number;
    	}
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
    	}
    }
    
    /**
      * @brief  OLED显示数字(十六进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
      * @param  Length 要显示数字的长度,范围:1~8
      * @retval 无
      */
    void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i, SingleNumber;
    	for (i = 0; i < Length; i++)							
    	{
    		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
    		if (SingleNumber < 10)
    		{
    			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
    		}
    		else
    		{
    			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
    		}
    	}
    }
    
    /**
      * @brief  OLED显示数字(二进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
      * @param  Length 要显示数字的长度,范围:1~16
      * @retval 无
      */
    void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
    	}
    }
    
    /**
      * @brief  OLED初始化
      * @param  无
      * @retval 无
      */
    void OLED_Init(void)
    {
    	uint32_t i, j;
    	
    	for (i = 0; i < 1000; i++)			//上电延时
    	{
    		for (j = 0; j < 1000; j++);
    	}
    	
    	OLED_I2C_Init();			//端口初始化
    	
    	OLED_WriteCommand(0xAE);	//关闭显示
    	
    	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
    	OLED_WriteCommand(0x80);
    	
    	OLED_WriteCommand(0xA8);	//设置多路复用率
    	OLED_WriteCommand(0x3F);
    	
    	OLED_WriteCommand(0xD3);	//设置显示偏移
    	OLED_WriteCommand(0x00);
    	
    	OLED_WriteCommand(0x40);	//设置显示开始行
    	
    	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常 0xA0左右反置
    	
    	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常 0xC0上下反置
    
    	OLED_WriteCommand(0xDA);	//设置COM引脚硬件配置
    	OLED_WriteCommand(0x12);
    	
    	OLED_WriteCommand(0x81);	//设置对比度控制
    	OLED_WriteCommand(0xCF);
    
    	OLED_WriteCommand(0xD9);	//设置预充电周期
    	OLED_WriteCommand(0xF1);
    
    	OLED_WriteCommand(0xDB);	//设置VCOMH取消选择级别
    	OLED_WriteCommand(0x30);
    
    	OLED_WriteCommand(0xA4);	//设置整个显示打开/关闭
    
    	OLED_WriteCommand(0xA6);	//设置正常/倒转显示
    
    	OLED_WriteCommand(0x8D);	//设置充电泵
    	OLED_WriteCommand(0x14);
    
    	OLED_WriteCommand(0xAF);	//开启显示
    		
    	OLED_Clear();				//OLED清屏
    }
    
    

    OLED.h

    #ifndef __OLED_H
    #define __OLED_H
    
    #include "stm32f10x.h"                  // Device header
    
    
    void OLED_Init(void);
    void OLED_Clear(void);
    void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
    void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
    void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
    void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    
    #endif
    
    

    OLED_Font.h

    #ifndef __OLED_FONT_H
    #define __OLED_FONT_H
    
    #include "stm32f10x.h"                  // Device header
    
    
    /*OLED字模库,宽8像素,高16像素*/
    const uint8_t OLED_F8x16[][16]=
    {
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//  0
    	
    	0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
    	
    	0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
    	
    	0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
    	0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
    	
    	0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
    	0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
    	
    	0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
    	0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
    	
    	0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
    	0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
    	
    	0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
    	
    	0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
    	0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
    	
    	0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
    	0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
    	
    	0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
    	0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
    	
    	0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
    	0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
    	
    	0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
    	0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
    	
    	0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
    	0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
    	
    	0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
    	
    	0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
    	0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
    	
    	0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
    	0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
    	
    	0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
    	0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
    	
    	0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
    	0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
    	
    	0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
    	0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
    	
    	0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
    	0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
    	
    	0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
    	0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
    	
    	0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
    	0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
    	
    	0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
    	
    	0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
    	
    	0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
    	0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
    	
    	0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
    	0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
    	
    	0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
    	0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
    	
    	0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
    	0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
    	
    	0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
    	0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
    	
    	0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
    	0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
    	
    	0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
    	
    	0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
    	0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
    	
    	0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
    	
    	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
    	0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
    	
    	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
    	0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
    	
    	0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
    	0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
    	
    	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
    	0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
    	
    	0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
    	
    	0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
    	0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
    	
    	0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
    	0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
    	
    	0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
    	
    	0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
    	0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
    	
    	0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
    	0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
    	
    	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
    	
    	0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
    	0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
    	
    	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
    	
    	0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
    	0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
    	
    	0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
    	0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
    	
    	0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
    	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
    	
    	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
    	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
    	
    	0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
    	0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
    	
    	0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
    	0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
    	
    	0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
    	0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
    	
    	0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
    	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
    	
    	0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
    	0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
    	
    	0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
    	0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
    	
    	0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
    	
    	0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
    	0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
    	
    	0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
    	
    	0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
    	
    	0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
    	0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
    	
    	0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
    	
    	0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
    	
    	0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
    	
    	0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
    	
    	0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
    	
    	0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
    	0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
    	
    	0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
    	0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
    	
    	0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
    	
    	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
    	
    	0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
    	
    	0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
    	0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
    	
    	0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
    	
    	0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
    	0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
    	
    	0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
    	0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
    	
    	0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
    	0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
    	
    	0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
    	0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
    	
    	0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
    	0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
    	
    	0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
    	0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
    	
    	0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
    	0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
    	
    	0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
    	
    	0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
    	0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
    	
    	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
    	
    	0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
    	0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
    	
    	0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
    };
    
    #endif
    
    

    四.输入捕获和输出比较区别

    输入比较:假设ARR=99,那你一共计数ARR+1个值,也就是100,CRR=30,如果是pwm模式1,也就是0-29是高电平,到了30就开始转化低电平,从30-99都是低电平,这过程中CNT不断++,虽然CNT最大值是65535,计65536个值,但是ARR设置在99,是从0一直计到99,一旦变成99立马就中断溢出,计数器自动清0,计数器(pwm)的更新频率也就是溢出频率,fx(更新频率)=fc(时钟频率)/PSC+1(预分频系数)/ARR+1(自动重装值),预分频器和自动重装ARR和CCR都有影子寄存器,如果没有设置的话,他们的值一改变就是立刻生效,如果要等到产生更新事件才变化的话。
    (2).用这个函数
    TIM_OC1PreloadConfig—–CCR,这里oc1只对应CCR1的影子寄存器操作。

    TIM_ARRPreloadConfig—–ARR
    TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);//这个函数第一个参数是定时器,第二个参数是改变的值,第三是更新事件生效还是立刻生效,TIM_PSCReloadMode_Immediate立刻生效。

    (3).同一个定时器内输出比较的通道只有CCR寄存器不一样,例如CCR1,CCR2,CCR3,CCR4,但是他们的PSC,ARR,CNT都是用的同一个,所以我们多路输出PWM时,只能改变CCR。

    输入捕获:
    (1).捕获频率(就是PWM每次输出的高低电平,如图一,这里捕获的PWM频率是上升沿的脉冲个数)或者占空比,测周法:fx(更新频率)=fc(时钟频率)/N(CCR的值),这里的fc是经过预分频之后的时钟频率就跟输出比较一样fc/PSC+1,可以记成fx=fc/PSC+1/N,然后CCR不是跟输出比较的一样,输出比较的是设置好了值,小于大于给高低电平,输入捕获的CCR是在设置好上升沿触发或者下降沿触发,设置好上升沿触发的话,就是图二中从1开始然后到2的期间,CNT不断自增,一但CNT到达2上升沿,就把CNT计数的值给CRR,所以这里CCR好比输出比较的ARR+1,但是这里输入捕获的CRR的值跟输出比较的值不一样的,这里N就相当于计数器计了多少个值,fc/计了多少个值就等于pwm的更新频率,例如pwm的更新频率是1000hz,使用内部时钟72Mhz,输入捕获的预分频系给72,那fc=1000000,数所以计数器计数的值就是fc/fx=N,1000000/1000=1000,所以平时输入捕获计数器计数了多少个值我门不用知道,就按照fc经过预分频之后然后除TIM_GetCapture1(TIM3)+1就可以了,TIM_GetCapture1是返回CRR的值,也就是计数器的值,然后这里要的计了多少个数,所以就+1。

    (2).测周法适合低频,测频法适合高频,测周法一般适合MHZ——15HZ左右,怎么看可以捕获多少,频率/计数器最大值,例如经过分频之后1000000HZ频率,然后处于计多少个数值,1000000/65536=15HZ,最小可以15HZ,经过测试1000000hz频率捕获10000HZ的误差不会很大,然后输入捕获得滤波,滤波一般选择0x00——0x80,经过测试0X0F滤波最大,但是延时高,采样容易抖动,捕获得频率会来回跳动,所以尽量靠小一点滤波适合的,延时也低的。

    (3).输入捕获和输出比较不能用同一个定时器,因为要设置的ARR和PSC不一样;然后定时器中断跟输出比较定时器也是不能一样,因为我尝试过定时器中断和输入捕获一起,中断1s亮灯,也就是一直让亮着,输入捕获写同一个函数里面,输入捕获触发中断的时候,让灯保持一直灭着,但是定时器一旦到时间了,就会开始去执行定时器的任务了去亮灯。

    (4).注意:这里输入捕获输入模式只有通道1才支持,也就是从模式那些只有通道1才可以设置。

    (5).然后在图二,3的位置设置下降沿触发,就是从1到3就是高电平期间,然后1到3/1到4就是占空比了。

    图一

    图二

    五.两路输出PWM,一路捕获代码

    功能:一路PWM输出通过按键控制电机转速,一路PWM输出进行输入捕获

    main.c

    #include "stm32f10x.h"  // Device header
    #include "OLED.h"
    #include "PWM.h"
    #include "Key.h"
    #include "Motor.h"
    #include "IC.h"
    
    uint8_t Keynum;
    int8_t Speed;
    uint8_t i;
    
    int main()
    {
    	OLED_Init();
    	Motor_Init();
    	Key_Init();
    	PWM_Init();
    	IC_Init();
    	OLED_ShowString(1,1,"Speed:");
    	OLED_ShowString(2,1,"Freq:00000hz");
    	OLED_ShowString(3,1,"Duty:00%");
    	PWM_SetCompare2(50);
    	PWM_SetPrescaler(72-1);
    	while(1)
    	{
    		Keynum = Key_Getnum();
    		if(Keynum == 1)
    		{
    			Speed =0;
    		}
    		if(Keynum == 2)
    		{
    			Speed +=20;
    			if(Speed > 100)
    			{
    				Speed = 0;
    			}
    		}
    		if(Keynum == 3)
    		{
    			Speed -=20;
    			if(Speed < -100)
    			{
    				Speed = 0;
    			}
    		}
    		OLED_ShowSignedNum(1,7,Speed,3);
    		OLED_ShowNum(2,6,IC_Freq(),5);
    		OLED_ShowNum(3,6,IC_Duty(),2);
    		Motor_SetSpeed(Speed);
    	}
    }
    
    

    PWM.c

    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStrcut;
    	GPIO_InitStrcut.GPIO_Mode=GPIO_Mode_AF_PP;//对于普通的开漏输出/推挽输出,引脚的控制权是来自输出数据寄存器,如果想让定时器来控制引脚,就需要使用复用开漏输出/复用推挽输出
    	GPIO_InitStrcut.GPIO_Pin=GPIO_Pin_1 |GPIO_Pin_2;
    	GPIO_InitStrcut.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStrcut);
    	
    	TIM_InternalClockConfig(TIM2);
    	
    	TIM_TimeBaseInitTypeDef TIM_InitStrcut;
    	TIM_InitStrcut.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_InitStrcut.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_InitStrcut.TIM_Period=100-1;	  //ARR
    	TIM_InitStrcut.TIM_Prescaler=720-1;  //PSC预分频器
    	TIM_InitStrcut.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM2,&TIM_InitStrcut); 
    	
    	
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	TIM_OCStructInit(&TIM_OCInitStruct);//在OCInit初始化函数中有很多参数,通用定时器用不上一些,但是不对这些值赋值的话会时PWM输出出错,所以我们可以用这个函数,它是自动赋值给OCInit函数的所有结构体变量,然后我们下面在修改需要的参数即可
    	//PWM模式1并且是向上计数,CNT<CCR的时候,REF置有效电平(高电平),CNT>=CCR的时候,REF置无效电平(低电平)
    	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式,TIM_OCMode_Timing冻结模式,TIM_OCMode_Active相等时电平置有效电平,TIM_OCMode_Inactive相等时电平置无效电平,TIM_OCMode_Toggle相等时电平翻转,TIM_OCMode_PWM1是PWM模式1,TIM_OCMode_PWM2是PWM模式2
    	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//TIM_OCPolarity_High是高极性,就是极性不翻转,REF波形直接输出,IM_OCPolarity_Low低极性,就是REF电平取反
    	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
    	TIM_OCInitStruct.TIM_Pulse=90;//设置CCR寄存器
    	TIM_OC2Init(TIM2,&TIM_OCInitStruct);
    	TIM_OC3Init(TIM2,&TIM_OCInitStruct);
    	
    	
    	TIM_Cmd(TIM2,ENABLE);
    }
    
    void PWM_SetCompare2(uint16_t Compare)//设置CCR2寄存器的值
    {
    	TIM_SetCompare2(TIM2,Compare);
    }
    
    void PWM_SetCompare3(uint16_t Compare)//设置CCR3寄存器的值
    {
    	TIM_SetCompare3(TIM2,Compare);
    }
    
    void PWM_SetPrescaler(uint16_t Prescaler)//设置PSC的值
    {
    	TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);//这个函数第一个参数是定时器,第二个参数是改变的值,第三是更新事件生效还是立刻生效,TIM_PSCReloadMode_Immediate立刻生效,TIM_PSCReloadMode_Update更新事件生效
    }
    
    

    PWM.h

    #ifndef __PWM_H
    #define __PWM_H
    
    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void);
    void PWM_SetCompare2(uint16_t Compare);
    void PWM_SetCompare3(uint16_t Compare);
    void PWM_SetPrescaler(uint16_t Prescaler);
    
    #endif
    
    

    IC.C

    #include "stm32f10x.h"                  // Device header
    
    void IC_Init(void)
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);
    	
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_TimeBaseInitStruct.TIM_Period=65536-1;
    	TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;
    	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
    	
    	TIM_ICInitTypeDef TIM_ICInitStruct;
    	TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
    	TIM_ICInitStruct.TIM_ICFilter=0x08;
    	TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;
    	TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
    	TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
    	TIM_ICInit(TIM3,&TIM_ICInitStruct);
    	
    	TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);
    
    	TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
    	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
    	
    	TIM_Cmd(TIM3,ENABLE);
    }
    
    int32_t IC_Freq(void)
    {
    	return 1000000/(TIM_GetCapture1(TIM3)+1);
    }
    
    int32_t IC_Duty(void)
    {
    	return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
    
    }
    
    

    IC.h

    #ifndef __IC_H
    #define __IC_H
    #include "stm32f10x.h"                  // Device header
    
    
    void IC_Init(void);
    int32_t IC_Freq(void);
    int32_t IC_Duty(void);
    
    #endif
    
    

    Delay.c

    #include "stm32f10x.h"
    
    /**
      * @brief  微秒级延时
      * @param  xus 延时时长,范围:0~233015
      * @retval 无
      */
    void Delay_us(uint32_t xus)
    {
    	SysTick->LOAD = 72 * xus;				//设置定时器重装值
    	SysTick->VAL = 0x00;					//清空当前计数值
    	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
    	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
    	SysTick->CTRL = 0x00000004;				//关闭定时器
    }
    
    /**
      * @brief  毫秒级延时
      * @param  xms 延时时长,范围:0~4294967295
      * @retval 无
      */
    void Delay_ms(uint32_t xms)
    {
    	while(xms--)
    	{
    		Delay_us(1000);
    	}
    }
     
    /**
      * @brief  秒级延时
      * @param  xs 延时时长,范围:0~4294967295
      * @retval 无
      */
    void Delay_s(uint32_t xs)
    {
    	while(xs--)
    	{
    		Delay_ms(1000);
    	}
    } 
    
    

    Delay.h

    #ifndef __DELAY_H
    #define __DELAY_H
    #include "stm32f10x.h"                  // Device header
    
    void Delay_us(uint32_t us);
    void Delay_ms(uint32_t ms);
    void Delay_s(uint32_t s);
    
    #endif
    
    

    Motor.c

    #include "stm32f10x.h"                  // Device header
    #include "PWM.h"
    
    
    void Motor_Init(void)
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	GPIO_InitTypeDef GPIO_InitStruct;
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化电机引脚
    	PWM_Init();//电机的PWM
    	
    	
    }
    
    void Motor_SetSpeed(int8_t Speed)//如果输入的值大于等于0就正转,小于等于0就反转
    {
    	if(Speed >= 0)
    	{
    		GPIO_SetBits(GPIOA,GPIO_Pin_4);
    		GPIO_ResetBits(GPIOA,GPIO_Pin_5);
    		PWM_SetCompare3(Speed);
    	}
    	else
    	{
    		GPIO_ResetBits(GPIOA,GPIO_Pin_4);
    		GPIO_SetBits(GPIOA,GPIO_Pin_5);
    		PWM_SetCompare3(-Speed);//CCR的值必须是正的,所以加个负号
    	}
    
    }
    
    

    Motor.h

    #ifndef __MOTOR_H
    #define __MOTOR_H
    #include "stm32f10x.h"                  // Device header
    
    void Motor_Init(void);
    void Motor_SetSpeed(int8_t Speed);
    
    #endif
    

    Key.c

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    
    void Key_Init(void)
    {
    	GPIO_InitTypeDef GPIOstruct;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    	GPIOstruct.GPIO_Mode=GPIO_Mode_IPU;
    	GPIOstruct.GPIO_Pin=(GPIO_Pin_1 | GPIO_Pin_10 | GPIO_Pin_11);
    	GPIOstruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB,&GPIOstruct);
    	
    }
    
    uint8_t Key_Getnum(void)
    {
    	uint8_t Keynum = 0;
    	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
    	{
    		Delay_ms(20);
    		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0);
    		Delay_ms(20);
    		Keynum=1;
    	}
    	
    	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == 0)
    	{
    		Delay_ms(20);
    		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == 0);
    		Delay_ms(20);
    		Keynum=2;
    	}
    	
    	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0)
    	{
    		Delay_ms(20);
    		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0);
    		Delay_ms(20);
    		Keynum=3;
    	}
    	
    	return Keynum;
    }
    
    

    Key.h

    #ifndef __KEY_H
    #define __KEY_H
    
    #include "stm32f10x.h"                  // 这里定义头文件是因为uint8_t在这里面才有
    void Key_Init(void);
    uint8_t Key_Getnum(void);
    
    
    #endif
    

    OLED.c

    #include "stm32f10x.h"
    #include "OLED_Font.h"
    
    /*引脚配置*/
    #define OLED_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
    #define OLED_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))
    
    /*引脚初始化*/
    void OLED_I2C_Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
     	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
     	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
     	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	
    	OLED_W_SCL(1);
    	OLED_W_SDA(1);
    }
    
    /**
      * @brief  I2C开始
      * @param  无
      * @retval 无
      */
    void OLED_I2C_Start(void)
    {
    	OLED_W_SDA(1);
    	OLED_W_SCL(1);
    	OLED_W_SDA(0);
    	OLED_W_SCL(0);
    }
    
    /**
      * @brief  I2C停止
      * @param  无
      * @retval 无
      */
    void OLED_I2C_Stop(void)
    {
    	OLED_W_SDA(0);
    	OLED_W_SCL(1);
    	OLED_W_SDA(1);
    }
    
    /**
      * @brief  I2C发送一个字节
      * @param  Byte 要发送的一个字节
      * @retval 无
      */
    void OLED_I2C_SendByte(uint8_t Byte)
    {
    	uint8_t i;
    	for (i = 0; i < 8; i++)
    	{
    		OLED_W_SDA(Byte & (0x80 >> i));
    		OLED_W_SCL(1);
    		OLED_W_SCL(0);
    	}
    	OLED_W_SCL(1);	//额外的一个时钟,不处理应答信号
    	OLED_W_SCL(0);
    }
    
    /**
      * @brief  OLED写命令
      * @param  Command 要写入的命令
      * @retval 无
      */
    void OLED_WriteCommand(uint8_t Command)
    {
    	OLED_I2C_Start();
    	OLED_I2C_SendByte(0x78);		//从机地址
    	OLED_I2C_SendByte(0x00);		//写命令
    	OLED_I2C_SendByte(Command); 
    	OLED_I2C_Stop();
    }
    
    /**
      * @brief  OLED写数据
      * @param  Data 要写入的数据
      * @retval 无
      */
    void OLED_WriteData(uint8_t Data)
    {
    	OLED_I2C_Start();
    	OLED_I2C_SendByte(0x78);		//从机地址
    	OLED_I2C_SendByte(0x40);		//写数据
    	OLED_I2C_SendByte(Data);
    	OLED_I2C_Stop();
    }
    
    /**
      * @brief  OLED设置光标位置
      * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
      * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
      * @retval 无
      */
    void OLED_SetCursor(uint8_t Y, uint8_t X)
    {
    	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
    	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
    	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
    }
    
    /**
      * @brief  OLED清屏
      * @param  无
      * @retval 无
      */
    void OLED_Clear(void)
    {  
    	uint8_t i, j;
    	for (j = 0; j < 8; j++)
    	{
    		OLED_SetCursor(j, 0);
    		for(i = 0; i < 128; i++)
    		{
    			OLED_WriteData(0x00);
    		}
    	}
    }
    
    /**
      * @brief  OLED显示一个字符
      * @param  Line 行位置,范围:1~4
      * @param  Column 列位置,范围:1~16
      * @param  Char 要显示的一个字符,范围:ASCII可见字符
      * @retval 无
      */
    void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
    {      	
    	uint8_t i;
    	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
    	for (i = 0; i < 8; i++)
    	{
    		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
    	}
    	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
    	for (i = 0; i < 8; i++)
    	{
    		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
    	}
    }
    
    /**
      * @brief  OLED显示字符串
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  String 要显示的字符串,范围:ASCII可见字符
      * @retval 无
      */
    void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
    {
    	uint8_t i;
    	for (i = 0; String[i] != '\0'; i++)
    	{
    		OLED_ShowChar(Line, Column + i, String[i]);
    	}
    }
    
    /**
      * @brief  OLED次方函数
      * @retval 返回值等于X的Y次方
      */
    uint32_t OLED_Pow(uint32_t X, uint32_t Y)
    {
    	uint32_t Result = 1;
    	while (Y--)
    	{
    		Result *= X;
    	}
    	return Result;
    }
    
    /**
      * @brief  OLED显示数字(十进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~4294967295
      * @param  Length 要显示数字的长度,范围:1~10
      * @retval 无
      */
    void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
    	}
    }
    
    /**
      * @brief  OLED显示数字(十进制,带符号数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:-2147483648~2147483647
      * @param  Length 要显示数字的长度,范围:1~10
      * @retval 无
      */
    void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	uint32_t Number1;
    	if (Number >= 0)
    	{
    		OLED_ShowChar(Line, Column, '+');
    		Number1 = Number;
    	}
    	else
    	{
    		OLED_ShowChar(Line, Column, '-');
    		Number1 = -Number;
    	}
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
    	}
    }
    
    /**
      * @brief  OLED显示数字(十六进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
      * @param  Length 要显示数字的长度,范围:1~8
      * @retval 无
      */
    void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i, SingleNumber;
    	for (i = 0; i < Length; i++)							
    	{
    		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
    		if (SingleNumber < 10)
    		{
    			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
    		}
    		else
    		{
    			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
    		}
    	}
    }
    
    /**
      * @brief  OLED显示数字(二进制,正数)
      * @param  Line 起始行位置,范围:1~4
      * @param  Column 起始列位置,范围:1~16
      * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
      * @param  Length 要显示数字的长度,范围:1~16
      * @retval 无
      */
    void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
    {
    	uint8_t i;
    	for (i = 0; i < Length; i++)							
    	{
    		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
    	}
    }
    
    /**
      * @brief  OLED初始化
      * @param  无
      * @retval 无
      */
    void OLED_Init(void)
    {
    	uint32_t i, j;
    	
    	for (i = 0; i < 1000; i++)			//上电延时
    	{
    		for (j = 0; j < 1000; j++);
    	}
    	
    	OLED_I2C_Init();			//端口初始化
    	
    	OLED_WriteCommand(0xAE);	//关闭显示
    	
    	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
    	OLED_WriteCommand(0x80);
    	
    	OLED_WriteCommand(0xA8);	//设置多路复用率
    	OLED_WriteCommand(0x3F);
    	
    	OLED_WriteCommand(0xD3);	//设置显示偏移
    	OLED_WriteCommand(0x00);
    	
    	OLED_WriteCommand(0x40);	//设置显示开始行
    	
    	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常 0xA0左右反置
    	
    	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常 0xC0上下反置
    
    	OLED_WriteCommand(0xDA);	//设置COM引脚硬件配置
    	OLED_WriteCommand(0x12);
    	
    	OLED_WriteCommand(0x81);	//设置对比度控制
    	OLED_WriteCommand(0xCF);
    
    	OLED_WriteCommand(0xD9);	//设置预充电周期
    	OLED_WriteCommand(0xF1);
    
    	OLED_WriteCommand(0xDB);	//设置VCOMH取消选择级别
    	OLED_WriteCommand(0x30);
    
    	OLED_WriteCommand(0xA4);	//设置整个显示打开/关闭
    
    	OLED_WriteCommand(0xA6);	//设置正常/倒转显示
    
    	OLED_WriteCommand(0x8D);	//设置充电泵
    	OLED_WriteCommand(0x14);
    
    	OLED_WriteCommand(0xAF);	//开启显示
    		
    	OLED_Clear();				//OLED清屏
    }
    
    

    OLED.h

    #ifndef __OLED_H
    #define __OLED_H
    
    #include "stm32f10x.h"                  // Device header
    
    
    void OLED_Init(void);
    void OLED_Clear(void);
    void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
    void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
    void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
    void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
    
    #endif
    
    

    OLED_Font.h

    #ifndef __OLED_FONT_H
    #define __OLED_FONT_H
    
    #include "stm32f10x.h"                  // Device header
    
    
    /*OLED字模库,宽8像素,高16像素*/
    const uint8_t OLED_F8x16[][16]=
    {
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//  0
    	
    	0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
    	
    	0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
    	
    	0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
    	0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
    	
    	0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
    	0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
    	
    	0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
    	0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
    	
    	0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
    	0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
    	
    	0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
    	
    	0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
    	0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
    	
    	0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
    	0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
    	
    	0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
    	0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
    	
    	0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
    	0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
    	
    	0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
    	0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
    	
    	0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
    	0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
    	
    	0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
    	
    	0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
    	0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
    	
    	0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
    	0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
    	
    	0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
    	0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
    	
    	0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
    	0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
    	
    	0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
    	0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
    	
    	0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
    	0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
    	
    	0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
    	0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
    	
    	0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
    	0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
    	
    	0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
    	
    	0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
    	
    	0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
    	0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
    	
    	0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
    	0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
    	
    	0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
    	0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
    	
    	0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
    	0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
    	
    	0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
    	0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
    	
    	0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
    	0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
    	
    	0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
    	
    	0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
    	0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
    	
    	0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
    	
    	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
    	0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
    	
    	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
    	0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
    	
    	0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
    	0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
    	
    	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
    	0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
    	
    	0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
    	
    	0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
    	0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
    	
    	0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
    	0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
    	
    	0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
    	0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
    	
    	0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
    	0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
    	
    	0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
    	0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
    	
    	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
    	
    	0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
    	0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
    	
    	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
    	0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
    	
    	0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
    	0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
    	
    	0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
    	0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
    	
    	0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
    	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
    	
    	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
    	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
    	
    	0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
    	0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
    	
    	0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
    	0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
    	
    	0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
    	0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
    	
    	0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
    	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
    	
    	0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
    	0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
    	
    	0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
    	0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
    	
    	0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
    	
    	0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
    	0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
    	
    	0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
    	
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
    	
    	0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
    	
    	0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
    	0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
    	
    	0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
    	
    	0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
    	
    	0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
    	
    	0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
    	
    	0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
    	
    	0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
    	0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
    	
    	0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
    	0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
    	
    	0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
    	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
    	
    	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
    	
    	0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
    	0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
    	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
    	
    	0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
    	0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
    	
    	0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
    	
    	0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
    	0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
    	
    	0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
    	
    	0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
    	0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
    	
    	0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
    	0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
    	
    	0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
    	0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
    	
    	0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
    	0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
    	
    	0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
    	0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
    	
    	0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
    	0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
    	
    	0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
    	0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
    	
    	0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
    	0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
    	
    	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
    	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
    	
    	0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
    	0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
    	
    	0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
    	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
    };
    
    #endif
    
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32输入捕获功能详解

    发表评论