stm32(F103c8t6)自学笔记@阿布君

这篇具有很好参考价值的文章主要介绍了stm32(F103c8t6)自学笔记@阿布君。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

学习过程中的注意点:

1.注意头文件和C文件的包含关系,C文件自身应包含自身的H头文件以及用到的外部头文件,而自身头文件只需包含头文件需要用到的资源文件即可。

参考文献:http://t.csdn.cn/o2GmL

一、认识STM32

1.简介

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.命名规则  

3.系统结构

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

4.引脚&功能

注释:

红色表示:与电源相关

蓝色是最小系统相关的引脚

绿色是IO口、功能口

S代表电源、I代表输入、O代表输出、IO代表输入输出、FT代表能容忍5v电压(没有就是3.3v)

芯片上小黑点旁为第一个IO口,逆时针增加;

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

5.启动配置 (BOOT三种模式)

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

6.实物电路连接及Keil的设置 (ST-Link)

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

二、软件环境安装(MDK)及新建工程

1.MDK的安装

stm32不同于C51,需要安装ARM_mdk的版本;

keil5及之后的版本需要安装芯片对应系列的器件库(pack);

stm的编程模式除了像单片机那样(1)直接操作寄存器(更可靠但是复杂、麻烦),还有通过(2)使用官方封装好的库函数,还有一种方法是(3)使用Hal库(如使用STM32CubeMX软件实现自动初始化配置)。

安装过程不在过多赘述,CSDN上有实现C51、ARM、C251三版共存的方法。

2.新建工程

因为采用的是使用官方封装好的库函数,所以并不像之前配置单片机那样去简单的只插入头文件然后写程序就好,而是先导入官方的启动文件,搭建环境。

2.1 配置成寄存器开发模式(工程)(详细步骤)

1.建立启动文件夹start,导入启动文件

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言
启动文件
stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言
必要头文件
stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言
内核的寄存器描述文件以及配置函数库
stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言
成为这样

        这里注意:上图中的md.s后缀文件是根据单片机型号选择的,参考下图

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.建立用户文件夹User

        创建main.c

3.完成

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.1.1 寄存器开发模式下实现点亮LED(GPIO13)

1.首先打开RCC寄存器的APB2使能GPIOC的时钟

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.再配置对应的GPIOC的模式

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

3.再写入该GPIOC的输出数据

        灯是低电平点亮,高电平熄灭

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

4.完成

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

5.总结收获

通过该方法配置很繁琐,且每次配置会影响其它IO口的数据,只能通过像单片机中的&=、|=来解决,更麻烦。

2.2 配置成标准库开发模式(工程)(详细步骤)

1.在寄存器开发模板的基础上,新建Lirary文件夹,导入c文件、头文件

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

         全部粘贴到刚建立的文件夹Library

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

        将这三个粘贴到User文件夹(下面需要在Keil里配置路径)

2.在Keil里添加上述文件,配置Keil

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

一定要定义 USE_STDPERIPH_DRIVER

        USE使用、下划线、STD标准、PERIPH外设、下划线、DRIVER驱动

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言
自己定义的带有头文件的文件夹都需要添加入路径

 3.完成!

编译0错误0警告

2.2.1 标准库开发模式下实现点亮LED(GPIO13)

配置思路和配置库函数一样,不同在于不用查手册看具体位以及担心改变其它位的数据了

操作流程还是一样的

1.使能RCC寄存器控制的APB2总线上的外设IO时钟

2.配置目标外设的模式

        这里注意:由于库函数定义的GPIO_Init函数需要传入一个结构体变量的地址,这里是将需要配置的 Pin口、Speed传输速度、Mode输出模式 三个封装在了结构体里以此简化了代码。我们调用前必须要先自定义该结构体类型的变量

3.配置GPIOC_Pin口输出的数据

    GPIO_SetBits (GPIOC,GPIO_Pin_13);  //输出高电平(熄灭)
    GPIO_ResetBits (GPIOC,GPIO_Pin_13);  //输出低电平(点亮)

#include "stm32f10x.h"                  // Device header


int main(void)
{
//	RCC->APB2ENR = 0X00000010;  //配置寄存器实现点灯
//	GPIOC->CRH = 0X00300000;
//	GPIOC->ODR = 0X00000000;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能GPIOC时钟
	GPIO_InitTypeDef GPIO_InitStruct;  //定义的结构体
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;  //输出模式
	GPIO_InitStruct .GPIO_Pin = GPIO_Pin_13;  //输出IO口
	GPIO_InitStruct .GPIO_Speed = GPIO_Speed_50MHz;  //输出速度
	GPIO_Init(GPIOC,&GPIO_InitStruct);  //配置GPIOC的模式,这里将三种模式放在了一个结构体内,因此要在上面定义一个结构体
	//GPIO_SetBits (GPIOC,GPIO_Pin_13);  //输出高电平(熄灭)
	GPIO_ResetBits (GPIOC,GPIO_Pin_13);  //输出低电平(点亮)
	while(1)
	{
		
	}
}

3.工程架构

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

4.步骤回顾、总结

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

三、GPIO(外设)

1.GPIO结构及原理

1.1 介绍

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.2 结构 

简单来说,GPIO是受RCC寄存器 控制的APB2总线上的一系列外设IO口。

这些IO口由 GPIO A~GPIO E ,而单个GPIO如GPIOC都是又下分为16个小IO口(引脚),其中驱动器是为了增加引脚电平驱动能力

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

单个外设口如GPIOC的内部电路结构如下:

        下图中的肖特基触发器是文献翻译错误,实际应为施密特触发器。

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

 施密特触发器原理:

        内部可设两个阈值,输入信号高于上限为高电平,低于下限为低电平

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.3 GPIO的八种模式

typedef enum
{ GPIO_Mode_AIN = 0x0,
  GPIO_Mode_IN_FLOATING = 0x04,
  GPIO_Mode_IPD = 0x28,
  GPIO_Mode_IPU = 0x48,
  GPIO_Mode_Out_OD = 0x14,
  GPIO_Mode_Out_PP = 0x10,
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

Stm32库里将8种模式定义为了枚举类型

  • GPIO_Mode_AIN:模拟输入模式(Analog Input Mode)。
  • GPIO_Mode_IN_FLOATING:浮空输入模式(Floating Input Mode)。
  • GPIO_Mode_IPD:下拉输入模式(Input Pull-down Mode)。
  • GPIO_Mode_IPU:上拉输入模式(Input Pull-up Mode)。
  • GPIO_Mode_Out_OD:开漏输出模式(Output Open-drain Mode)。
  • GPIO_Mode_Out_PP:推挽输出模式(Output Push-pull Mode)。
  • GPIO_Mode_AF_OD:复用开漏输出模式(Alternate Function Output Open-drain Mode)。
  • GPIO_Mode_AF_PP:复用推挽输出模式(Alternate Function Output Push-pull Mode)。

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.GPIO输出

2.1 可输出设备(LED、蜂鸣器...)

和51单片机一样,每个IO口都具有输出功能(高低电平)

因此可实现点亮LED,蜂鸣器报警等功能。

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.2Stm32中LED、蜂鸣器的电路

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.3 面包板(结构)

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.4 实现LED闪烁(含代码)

一定要先按照自己的思路和理解去写一遍,主要就是调用各种库函数。

下面代码需要注意的是:

GPIO_InitTypeDef A,B,C;  //定义三个IO的结构体变量 A是PA0口、B是PA1口、C是PA3口

这段代码如果在函数中间定义会报错,那么是由于你的Keil版本过低导致,按下图设置:

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE );//使能GPIO时钟
	
	GPIO_InitTypeDef A,B,C;  //定义三个GPIO的结构体变量 A是GPIOA、B是GPIOB、C是GPIOC//这里理解也不对,因为ABC只在RCC那里使能打开,这里定义的只是变量名,只是一个中间媒介去实现传值

	A.GPIO_Mode=GPIO_Mode_Out_PP;//设置为推挽输出模式
	A.GPIO_Pin=GPIO_Pin_0;  //设置为Pin0口
	A.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz
	GPIO_Init( GPIOA,&A); //以上三个都要传入该函数初始化
	
	B.GPIO_Mode=GPIO_Mode_Out_PP;
	B.GPIO_Pin=GPIO_Pin_1;
	B.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init( GPIOA,&B);
	
	C.GPIO_Mode=GPIO_Mode_Out_PP;
	C.GPIO_Pin=GPIO_Pin_2;
	C.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init( GPIOA,&C);
	while(1)
	{
		GPIO_ResetBits (GPIOA,GPIO_Pin_0);//先亮
		GPIO_ResetBits (GPIOA,GPIO_Pin_1);
		GPIO_ResetBits (GPIOA,GPIO_Pin_2);
		Delay_ms(500);
		GPIO_SetBits (GPIOA,GPIO_Pin_0);//再灭
		GPIO_SetBits (GPIOA,GPIO_Pin_1);
		GPIO_SetBits (GPIOA,GPIO_Pin_2);
		Delay_ms(500);
	}
}

不知道你是否发现,其实代码里是定义了三个外设,每个外设又单独设置的IO,其实这种方法是不对的,也是初学时容易产生的误区,如何修改,看下面的代码。

2.5 实现LED流水灯(含代码、理解

 初始化时是初始化一个外设,然后一个外设又有16个引脚。

上面的代码中 GPIO_InitTypeDef A,B,C;  //定义三个GPIO的结构体变量 A是GPIOA、B是GPIOB、C是GPIOC

这里理解也不对,因为ABC只在RCC寄存器那里使能打开,这里定义的只是变量名,只是一个中间媒介去实现传值

个人觉得这样定义可以实现一个外设例如GPIOA的16个引脚可以设置为不同的输出模式。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE );//使能GPIO时钟
	
	GPIO_InitTypeDef A;  //定义一个中间结构体变量

	A.GPIO_Mode=GPIO_Mode_Out_PP;//设置为推挽输出模式
	A.GPIO_Pin=GPIO_Pin_All;  //设置所有的Pin口(PA0~PA15)
	A.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz
	GPIO_Init( GPIOA,&A); //以上三个都要传入该函数初始化
	
	while(1)
	{
		unsigned char i;
		for(i=0;i<8;i++)
		{
			GPIO_Write(GPIOA ,~(0X0001<<i));//0000 0000 0000 0001依次左移8位 该函数可以整体写入GPIOx->ODR
			Delay_ms(100);
		}
	}
}

2.6 蜂鸣器(含代码)

 配置原理和配LED是一样的

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE );//使能GPIO时钟
	
	GPIO_InitTypeDef A;

	A.GPIO_Mode=GPIO_Mode_Out_PP;//设置为推挽输出模式
	A.GPIO_Pin=GPIO_Pin_12;  //设置为Pin0口
	A.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz
	GPIO_Init( GPIOB,&A); //以上三个都要传入该函数初始化
	while(1)
	{
		GPIO_ResetBits(GPIOB,GPIO_Pin_12);//低电平触发
		Delay_ms (100);
		GPIO_SetBits(GPIOB,GPIO_Pin_12);//不响
		Delay_ms (100);
	}
}

3.GPIO输入

3.1 可输入设备(按键、温湿度...)

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

3.2 Stm32中按键、红外发射等器件的电路

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

3.3 复习数据类型、宏定义、Typedef、结构体、枚举

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

 define能改变任何数据的名字,但是编译器不会检测是否有错

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

 Typedef结构体相关的用法和说明可以看我的另外一篇文章

http://t.csdn.cn/H8ikF

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

枚举类似于结构体,其中关键词 enum相当于结构体的关键词 struct

注意enum中是用逗号分隔;

枚举的作用就是限制变量值的输入取值范围,就像星期几只能从七天里选一个;

取值超出范围会报错;

下附释义代码

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

#include <stdio.h>

int main()
{
	typedef enum{ 
		mon=1,
		tur, //	等效于mon=1,tur=2,wen=3,tue=4
		wen,
		tue
	}day;//这里将整个枚举改名为day 
	day a,b,c;
	int d;
	
	a=tur;
	b=(day)1;//直接赋值int型不行 ,需要转化为枚举型 
	c=day(4);
	
	d=wen;//外界数据也可以引用枚举集合里的数 
	
	printf("a=%d\n",a);
	printf("b=%d\n",b);
	printf("c=%d\n",c);
	printf("d=%d\n",d);
 } 

3.4 代码(按键控制LED)(封装)(Delay函数封装)

Stm32中延时函数Delay的us、ms、s的代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"

/***************************************************/延时函数模块
#include "Delay.h"
#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);
	}
} 

/***************************************************/LED模块
#include "LED.h"
#include "stm32f10x.h"                  // Device header

void LED_init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE );//使能GPIOA的时钟
	
	GPIO_InitTypeDef A;  //定义两个IO的结构体变量 A是PA0口、B是PB0口

	A.GPIO_Mode=GPIO_Mode_Out_PP;//设置为推挽输出模式
	A.GPIO_Pin=GPIO_Pin_All;  //设置为所有Pin口
	A.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz
	GPIO_Init( GPIOA,&A); //以上三个都要传入该函数初始化
	
}

void LED_state(uint16_t GPIO_Pin,FunctionalState NewState)//指定Pin口和对应状态
{
	if(NewState==0)
		GPIO_ResetBits(GPIOA,GPIO_Pin);//置低电平
	else
		GPIO_SetBits(GPIOA,GPIO_Pin);//置高电平
}

/***************************************************/按键模块
#include "Key.h"                  // Device header
#include "Delay.h"


void Key_init(uint16_t GPIO_Pin)//需要指定端口Pin进行模式设置
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE );//使能GPIOA的时钟
	
	GPIO_InitTypeDef A;  //定义两个IO的结构体变量 A是PA0口、B是PB0口

	A.GPIO_Mode=GPIO_Mode_IPU;//设置为 上拉输入 模式
	A.GPIO_Pin=GPIO_Pin;  //外界参数设置Pin口
	A.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz,在输入模式下该设置没用
	GPIO_Init( GPIOB,&A); //以上三个都要传入该函数初始化
}

uint8_t get_keynum(uint16_t GPIO_Pin)
{
	uint8_t keynum;
	keynum =GPIO_ReadInputDataBit(GPIOB,GPIO_Pin);
	if(keynum ==0)
	{
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin) ==0);
		Delay_ms(10);
		return 0;
	}
	else 
		return keynum ;
}

/***************************************************/主函数
int main(void)
{
	uint8_t state=0;
	LED_init();
	Key_init(GPIO_Pin_12);
	while(1)
	{
		if(get_keynum(GPIO_Pin_12) ==0)
		{
			state ++;
		}
		if(state %2)
		{
			LED_state(GPIO_Pin_All ,ENABLE);
		}
		else 
		{
			LED_state(GPIO_Pin_All,DISABLE);
		}
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

3.5 代码(光敏电阻控制蜂鸣器及LED)(封装)

#include "stm32f10x.h"                  // Device header
#include "Buzzer.h"
#include "LightR.h"
#include "LED.h"


/***************************************************/蜂鸣器模块
#include "Buzzer.h"                  // Device header
#include "stm32f10x.h" 

GPIO_InitTypeDef buzzer;  

void Buzzer_init(uint16_t GPIO_Pin)//需要指定端口Pin进行模式设置
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE );//使能GPIOB的时钟
	
	

	buzzer.GPIO_Mode=GPIO_Mode_Out_PP;//设置为推挽输出模式
	buzzer.GPIO_Pin=GPIO_Pin;  //外界参数设置Pin口
	buzzer.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz,在输入模式下该设置没用
	GPIO_Init( GPIOB,&buzzer); //以上三个都要传入该函数初始化
}

void Buzzer_run(unsigned char Flag)//设定运行标志位
{
	if(Flag==0)
		GPIO_ResetBits(GPIOB,buzzer.GPIO_Pin);//置低电平
	else
		GPIO_SetBits(GPIOB,buzzer.GPIO_Pin);//置高电平
}

/***************************************************/光敏电阻模块
#include "LightR.h"
#include "stm32f10x.h" 

GPIO_InitTypeDef lightr;  

void LightR_init(uint16_t GPIO_Pin)//需要指定端口Pin进行模式设置
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);//使能GPIOB的时钟
	
	

	lightr.GPIO_Mode=GPIO_Mode_IPU;//设置为 上拉输入 模式
	lightr.GPIO_Pin=GPIO_Pin;  //外界参数设置Pin口
	lightr.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz,在输入模式下该设置没用
	GPIO_Init( GPIOB,&lightr); //以上三个都要传入该函数初始化
}

uint8_t get_LightR_DO(void)//用来获取光敏电阻输出的数字量DO值
{
	return  GPIO_ReadInputDataBit(GPIOB,lightr.GPIO_Pin);
}

/***************************************************/LED模块
#include "LED.h"
#include "stm32f10x.h"                  // Device header

GPIO_InitTypeDef led;  //定义两个IO的结构体变量 A是PA0口、B是PB0口

void LED_init(uint16_t GPIO_Pin)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE );//使能GPIOA的时钟
	
	
	led .GPIO_Mode=GPIO_Mode_Out_PP;//设置为推挽输出模式
	led .GPIO_Pin=GPIO_Pin;  //设置为所有Pin口
	led .GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz
	GPIO_Init( GPIOA,&led ); //以上三个都要传入该函数初始化
	
}

void LED_state(unsigned char Flag)//指定Pin口和对应状态
{
	if(Flag==0)
		GPIO_ResetBits(GPIOA,led.GPIO_Pin);//置低电平
	else
		GPIO_SetBits(GPIOA,led.GPIO_Pin);//置高电平
}

/***************************************************/主函数

int main(void)
{
	uint16_t lightstate;//亮、暗状态
	
	LED_init(GPIO_Pin_0);
	Buzzer_init(GPIO_Pin_0);
	LightR_init(GPIO_Pin_1);
	while(1)
	{
		lightstate =get_LightR_DO();//循环里实时获取
		if(lightstate)//暗	灯灭、蜂鸣器响
		{
			LED_state(1);
			Buzzer_run(0);
		}
		else //亮	灯亮、蜂鸣器不响
		{
			LED_state(0);
			Buzzer_run(1);
		}
	}
}

/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

四、OLED显示屏

1.结构原理

1.1 结构图(0.96寸4针B版本)

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.2 介绍

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.3 电路

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.4 调试方法

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.OLED驱动函数

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

3.驱动函数封装包

见资源包

五、EXTI外部中断系统

1.结构原理

1.1 认识中断

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

和C51中的中断是一样的,只不过32的资源更加丰富;  stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.2 中断系统内部机制(中断和异常向

         由于Stm32中断资源众多,所以这里的中断都是由NVIC统一管理。

左边需要执行的众多中断会根据分组和优先级排队,其中抢占优先级具有最高优先级可直接由NVIC传入CPU,中断CPU正在执行的主程序或者中断),而响应优先级则具有插队排第一位的权限优先级次于抢占优先级),当左边排队完成,NVIC会根据左边的排队决定当前该执行哪一个中断然后传给CPU(CPU不知道优先级逻辑,由NVIC处理,节约算力和IO口

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

 中断和异常向表,建议翻看手册;

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.3 EXTI简介

触发中断,中断响应是正常的流程,但是Stm32还提供了一种额外的中断处理:事件响应

当选择触发事件响应,那么该中断信号将不会通过NVIC传入CPU,而是直接传给某一个外设并触发它。例如触发ADC模块‘触发DMA等。

总结:中断响应是正常的流程,引脚电平变化触发中断。事件响应不会触发中断,而是触发别的外设操作,属于外设之间的联合操作。

注意:相同的pin口的中断不能同时被触发,如PA0、PB0、PC0三个中断同时需要传入NVIC,但是最终只会有一个被传入。

在EXTI内部有对数据筛选处理的模块,最终只有指定的IO数据会传入NVIC,其它的会作为事件触发传给指定的外设。

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.4 EXTI机制

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.5 AFIO复用IO口

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.点触式旋转编码器

2.1 结构原理

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

 2.2 代码实现(详细步骤说明)

该模块需要用到中断,如何实现呢?其实原理就是将模块IO口使能使其数据能够到达NVIC再到CPU就好了。

五个步骤:

1.打开对应IO口的RCC外设时钟(不打开IO口不能工作);

2.配置IGPO口的模式;

3.配置AFIO,使其选择我们要用的GPIO口,连接到EXTI;

4.配置EXTI模式,选择触发方式及响应方式(中断or事件);

5.配置NVIC,选择一个合适的中断优先级。

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "mokuaicount.h"
extern int num;

/***************************************************/初始化旋钮模块
#include "xuanniu.h"                  // Device header
#include "stm32f10x.h" 

void Xuanniu_init(uint16_t GPIO_Pin)//需要指定端口Pin进行模式设置
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);//使能GPIOA的时钟
	
	GPIO_InitTypeDef Xuanniu_InitStruct;  

	Xuanniu_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//设置为 上拉输入 模式
	Xuanniu_InitStruct.GPIO_Pin=GPIO_Pin;  //外界参数设置Pin口
	Xuanniu_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz,在输入模式下该设置没用
	GPIO_Init( GPIOA,&Xuanniu_InitStruct); //以上三个都要传入该函数初始化
}

/***************************************************/配置中断
//**该模块由中断函数实现,可接入任意输入模式的模块实现计数
//**这里引入Key实现数据的减法,LightR实现加法
#include "stm32f10x.h"                  // Device header
#include "mokuaicount.h"
#include "Delay.h"
#include "xuanniu.h"


int num;

void Count_interrupt_init(void)
{
	//1、2、**步骤一二在模块内已经实现
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//AFIO时钟需要使能
	
	Xuanniu_init(GPIO_Pin_0|GPIO_Pin_1);
	//3**配置AFIO,选择输入引脚
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//Xuanniu旋钮
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
	//4**配置EXTI寄存器,选择触发方式,这里配置EXTI和GPIO一样需要定义一个结构体
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line=EXTI_Line0|EXTI_Line1;
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStruct);
	//5**配置NVIC,选择合适的中断优先级 --------每一个外设要单独配置
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//要先分组,整个系统NVIC只分配一种模式
	//**配置Xuanniu A端
	NVIC_InitTypeDef NVIC_InitStruct_Xuanniu;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI0_IRQn;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct_Xuanniu);
	//**配置Xuanniu C端
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI1_IRQn;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct_Xuanniu);
	
	
	//****所有配置完成
}

//中断位置随便放,也不需要声明
void EXTI0_IRQHandler()//正转触发
{
	if(EXTI_GetITStatus(EXTI_Line0)==SET)
	{
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0)
		{
			if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)==1)
			{
				num++;
			}
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI1_IRQHandler()
{
	if(EXTI_GetITStatus(EXTI_Line1)==SET)
	{
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)==0)
		{
			if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
			{
				num--;
			}
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line1);
}


/***************************************************/主函数
int main(void)
{
	OLED_Init();
	Count_interrupt_init();
	OLED_ShowString(1,1,"Hello,my honey");
	OLED_ShowString(2,1,"Hello WangFang");
	OLED_ShowString(3,1,"Hello Tomorrow");
	while(1)
	{
		OLED_ShowSignedNum(4,1,num,5);
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

六、TIM定时中断

1.结构原理

1.1 介绍

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.2 定时器种类

不同型号的开发板拥有的定时器资源不一样

基本定时器只支持向上计数(由0加到重装载值触发中断后清零)

通用定时器和高级定时器都支持向上计数、向下计数、中央对齐三种模式计数

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.3 基本定时器框图

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.4 通用定时器框图

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.5 高级定时器框图

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.6 定时中断基本结构

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.7 时序图(详细解释)

计数流程:选择时钟源-->确定滤波的几分频-->确定预分频PSC-->确定重装载值ARR-->溢出触发中断

分频过程:外部输入规律的高低电平脉冲信号,经过选择分频模式后,信号转化输入预分频器开始计数,每到达预分频器设置的阈值溢出时就产生一个脉冲给计数器,计数器+1,最后当计数器计数值等于自动装载器设置的阈值时产生溢出,触发中断,因此在一分频模式下:

定时频率(时间)=(预分频值/初始时钟频率)*预装载值

如定时1s,则1 s=(7200)/72Mhz * 10000                     (取值范围 0~65535)

这就像是两个定时器级联一样,增大了计数范围

最新理解:

已知公式 t=1/f

那么内部时钟经过预分频后每记一次的时间就为:t1=1/(72Mhz/PSC+1)

那么分频器每隔t1时间就产生信号给计数器,直到计数器经过t2=t1*(ARR+1)的时间或者说累加到等于ARR时,产生中断同时计数器清零。

所以整个过程花费时间(每次中断的间隔时间)为:t2=1/(72Mhz/PSC+1)*(ARR+1)

比如要计时 1s :1 s = 1 / ( 72Mhz / 7200)* 10000

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.定时器中断计数(代码)

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "timer2.h"

/***************************************************/定时器2
#include "stm32f10x.h"
#include "timer2.h"

extern int num;
void timer2_init(void)
{
	//**1.打开总的RCC
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
	//**2.选定定时器接入的时钟
	TIM_InternalClockConfig(TIM2);//设置定时器2使用内部时钟,可不写,上电默认
	//**3.配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
	TIM_TimeBaseInitStruct.TIM_Period=10000-1;//设置预装载值
	TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除
	//**4.使能时基单元的中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	//**5.配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组
	
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStruct);
	//**6.开始计数
	TIM_Cmd(TIM2,ENABLE);

}

//**配置中断函数
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		num++;
	}
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//一定要清除标志位
}

/***************************************************/主函数

int num;
int main(void)
{
	OLED_Init();
	timer2_init();
	OLED_ShowString(1,1,"Hello,my honey");
//	OLED_ShowString(2,1,"Hello WangFang");
//	OLED_ShowString(3,1,"Hello Tomorrow");
//	OLED_ShowString(4,1,"I miss you");
	while(1)
	{
		OLED_ShowString(2,1,"NUM:");
		OLED_ShowNum(2,5,num,5);
		
		OLED_ShowString(3,1,"Prescaler:");
		OLED_ShowNum(3,11,TIM_GetPrescaler(TIM2),5);
		
		OLED_ShowString(4,1,"Counter:");
		OLED_ShowNum(4,9,TIM_GetCounter(TIM2),5);
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

3.外部时钟的定时器中断(代码)

相对于2的使用内部时钟,此方法不同之处仅在于使用函数:

TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//第二个设置分频,第三个设置触发方式,第四个设置采样频率(滤波器)

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "timer2.h"

/***************************************************/定时器2
#include "stm32f10x.h"
#include "timer2.h"

extern int num;
void timer2_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//**2.配置定时器接入外部时钟 同时配置外部时钟输入的引脚
	//TIM_InternalClockConfig(TIM2);//设置定时器2使用内部时钟,可不写,上电默认
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//第二个设置分频,第三个设置触发方式,第四个设置采样频率(滤波器)
	//**3.配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
//	TIM_TimeBaseInitStruct.TIM_Period=10000-1;//设置预装载值       //外部时钟的话用不了这么高的频率
//	TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_Period=10-1;//设置预装载值
	TIM_TimeBaseInitStruct.TIM_Prescaler=2-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除
	//**4.使能时基单元的中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	//**5.配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组
	
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStruct);
	//**6.开始计数
	TIM_Cmd(TIM2,ENABLE);

}

//**配置中断函数
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		num++;
	}
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

}


/***************************************************/主函数

int num;
int main(void)
{
	OLED_Init();
	timer2_init();
	OLED_ShowString(1,1,"Hello,my honey");
//	OLED_ShowString(2,1,"Hello WangFang");
//	OLED_ShowString(3,1,"Hello Tomorrow");
//	OLED_ShowString(4,1,"I miss you");
	while(1)
	{
		OLED_ShowString(2,1,"NUM:");
		OLED_ShowNum(2,5,num,5);
		
		OLED_ShowString(3,1,"Prescaler:");
		OLED_ShowNum(3,11,TIM_GetPrescaler(TIM2),5);
		
		OLED_ShowString(4,1,"Counter:");
		OLED_ShowNum(4,9,TIM_GetCounter(TIM2),5);
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

4.TIM(OC)比较输出(PWM)!!!

4.1 结构原理介绍(模式)

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

 8种模式

 TIM_OCMode                        函数库描述                             解释


TIM_OCMode_Timing       TIM输出比较                      冻结,输出比较不起作用
TIM_OOCMode_Active     TIM输出比较主动模式        当比较发生时,强制输出高电平
TIM_OCMode_Inactiive    TIM输出比较非主动模式     当比较发生时,强制输出低电平
TIM_OCMode_Toggle       TIM输出比较触发模式        当比较发生时,输出翻转
TIM_OCMode_PWM1        TIM脉冲宽度调制模式1      PWM1
TIM_OCMode_PWM2        TIM脉冲宽度调制模式2      PWM2

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

4.2 输出设备(舵机,直流电机)

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

4.3 代码配置

4.3.1(呼吸灯、重映射)

先和配置定时器步骤差不多,只不过最后不需要配置中断和NVIC,就直接配置CCR

CCR需要先使用TIM_OCStructInit()整体初始化,然后再单独配置需要的模式:

    TIM_OCInitTypeDef TIM_OCInitStruct;
    TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
    TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
    TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
    TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
    TIM_OCInitStruct.TIM_Pulse=100;//配置CCR计数器值
    TIM_OC1Init(TIM2,&TIM_OCInitStruct);

重映射使用看视频学习

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "PWM.h"
/***************************************************/PWM模块
#include "stm32f10x.h"                  // Device header
#include "Delay.h"


void pwm_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//**2.配置PWM输出引脚
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//**3.配置时基单元
	//配置为1000KHz,分辨率为1%
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
	TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
	TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

	//**4.配置CCR
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
	TIM_OCInitStruct.TIM_Pulse=100;//配置CCR计数器值
	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
	
	//5.开始计数
	TIM_Cmd(TIM2,ENABLE);
}

void LED_run(void)
{
	uint16_t num;
	for(num=100;num>0;num--)
	{
		TIM_SetCompare1(TIM2,num);
		Delay_ms(10);

	}
	for(num=0;num<100;num++)
	{
		TIM_SetCompare1(TIM2,num);
		Delay_ms(10);
	}
}

/***************************************************/主函数

int main(void)
{
	OLED_Init();
	pwm_init();
	OLED_ShowString(1,1,"Hello,my honey");
//	OLED_ShowString(2,1,"Hello WangFang");
//	OLED_ShowString(3,1,"Hello Tomorrow");
//	OLED_ShowString(4,1,"I miss you");
	while(1)
	{
		LED_run();
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/
4.3.2(旋钮控制舵机角度PWM)

旋转旋钮触发中断从而改变CCR的值(改变占空比)

要注意舵机的信号周期为20ms,既50Hz

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "PWM.h"
#include "mokuaicount.h"

/***************************************************/PWM模块
#include "stm32f10x.h"                  // Device header
#include "PWM.h"
#include "Delay.h"


void pwm_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//**2.配置PWM输出引脚PA0
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//**3.配置时基单元
	//配置为1000KHz,分辨率为1%
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
	TIM_TimeBaseInitStruct.TIM_Period=20000-1;//设置预装载值       //外部时钟的话用不了这么高的频率
	TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

	//**4.配置CCR
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_Pulse=0;
	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
	
	//5.
	//**6.开始计数
	TIM_Cmd(TIM2,ENABLE);
}

void set_angle(uint16_t angle)
{
	TIM_SetCompare1(TIM2,angle);
}

/***************************************************/GPIO初始化
#include "xuanniu.h"                
#include "stm32f10x.h" 

void Xuanniu_init(uint16_t GPIO_Pin)//需要指定端口Pin进行模式设置
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);//使能GPIOA的时钟
	
	GPIO_InitTypeDef Xuanniu_InitStruct;  

	Xuanniu_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//设置为 上拉输入 模式
	Xuanniu_InitStruct.GPIO_Pin=GPIO_Pin;  //外界参数设置Pin口
	Xuanniu_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz,在输入模式下该设置没用
	GPIO_Init( GPIOB,&Xuanniu_InitStruct); //以上三个都要传入该函数初始化
}

/***************************************************/计数模块
//**该模块由中断函数实现,可接入任意输入模式的模块实现计数
//**这里引入Key实现数据的减法,LightR实现加法
#include "stm32f10x.h"                  // Device header
#include "mokuaicount.h"
#include "Delay.h"
#include "xuanniu.h"


extern int num;

void Count_interrupt_init(void)
{
	//1、2、**步骤一二在模块内已经实现
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//AFIO时钟需要使能
	
	Xuanniu_init(GPIO_Pin_0|GPIO_Pin_1);
	//3**配置AFIO,选择输入引脚PB1(C),PB0(A)
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);//Xuanniu旋钮
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
	//4**配置EXTI寄存器,选择触发方式,这里配置EXTI和GPIO一样需要定义一个结构体
	EXTI_InitTypeDef EXTI_InitStruct;
	EXTI_InitStruct.EXTI_Line=EXTI_Line0|EXTI_Line1;
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStruct);
	//5**配置NVIC,选择合适的中断优先级 --------每一个外设要单独配置
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//要先分组,整个系统NVIC只分配一种模式
	//**配置Xuanniu A端
	NVIC_InitTypeDef NVIC_InitStruct_Xuanniu;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI0_IRQn;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct_Xuanniu);
	//**配置Xuanniu C端
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI1_IRQn;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct_Xuanniu);
	
	
	//****所有配置完成
}

//中断位置随便放,也不需要声明
void EXTI0_IRQHandler()//正转触发
{
	if(EXTI_GetITStatus(EXTI_Line0)==SET)
	{
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
		{
			if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1)
			{
				num+=100;
			}
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI1_IRQHandler()
{
	if(EXTI_GetITStatus(EXTI_Line1)==SET)
	{
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)
		{
			if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==1)
			{
				num-=100;
			}
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line1);
}


/***************************************************/主函数
int num=1500;

int main(void)
{
	OLED_Init();
	pwm_init();
	Count_interrupt_init();
	OLED_ShowString(1,1,"Hello,my baby");
	set_angle(num);//默认居中
	while(1)
	{	
		if(num<=0)
		{
			num=0;
			OLED_ShowString(2,8,"Left Max ");
		}
		else if(num<1500)
		{
			OLED_ShowString(2,8,"Left     ");
		}
		else if(num==1500)
		{
			OLED_ShowString(2,8,"Midel    ");
		}
		else if(num<2500)
		{
			OLED_ShowString(2,8,"Right    ");
		}
		else if(num>=2500)
		{
			num=2500;
			OLED_ShowString(2,8,"Right Max");
		}
		OLED_ShowNum(2,1,num,5);
		
		set_angle(num);
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/
4.3.3 直流电机(调速)

stay待机控制直接接入高电平3.3v就可以了

in1、in2初始化GPIO(推完输出模式)然后设置高低电平即可

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Motor.h"

/***************************************************/PWM模块
#include "stm32f10x.h"                  // Device header
#include "PWM.h"
#include "Delay.h"


void pwm_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//**2.配置PWM输出引脚PA0
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//**3.配置时基单元
	//配置为1000KHz,分辨率为1%
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
	TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
	TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

	//**4.配置CCR
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_Pulse=0;
	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
	
	//5.开始计数
	TIM_Cmd(TIM2,ENABLE);
}

void set_num(uint16_t num)
{
	TIM_SetCompare1(TIM2,num);
}

/***************************************************/电机模块
#include "stm32f10x.h"                  // Device header
#include "Motor.h"
#include "PWM.h"

void Motor_init(void)
{
	pwm_init();
	
	GPIO_InitTypeDef GPIO_InitStruct;//初始化两个方向控制引脚:PA4,PA5
	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);
	GPIO_Init(GPIOA,&GPIO_InitStruct);
}

void set_speed(int speed)
{
	if(speed>=0)
	{
		set_num(speed);
		GPIO_SetBits(GPIOA,GPIO_Pin_4);
		GPIO_ResetBits(GPIOA,GPIO_Pin_5);
	}
	else
	{
		set_num(-speed);
		GPIO_SetBits(GPIOA,GPIO_Pin_5);
		GPIO_ResetBits(GPIOA,GPIO_Pin_4);
	}
}

/***************************************************/主函数


int main(void)
{
	OLED_Init();
	Motor_init();
	while(1)
	{	
		set_speed(-100);
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

5.TIM输入捕获

5.1 结构原理

利用定时器模块计数,当输入捕获模块的边沿检测模块检测到下降沿或上升沿,触发获取CNT的值,每记完一次后CNT清零,获取到的该周期的CNT值再通过与CNT计数频率即可得到该电平变化周期的时间T。

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

由此可见,测频法适合测量高频,测周法适合测量低频 

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言 

5.2 代码配置

5.2.1 单通道测频率

这里采用TIM2产生PWM信号用于测量

配置TIM3时,也需要配置定时器时基模块使CNT计数,然后配置IC模块(通过一个结构体),再配置从模式的触发源和触发事件,使能定时器即可。

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "PWM.h"
#include "IC.h"

/***************************************************/PWM模块
#include "stm32f10x.h"                  // Device header


void pwm_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//**2.配置PWM输出引脚
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//**3.配置时基单元
	//配置为1000KHz,分辨率为1%
	TIM_InternalClockConfig(TIM2);//选择内部时钟源
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
	TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
	TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

	//**4.配置CCR
	TIM_OCInitTypeDef TIM_OCInitStruct;
	
	TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
	TIM_OCInitStruct.TIM_Pulse=0;//配置初始CCR计数器值
	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
	
	//**5.开始计数
	TIM_Cmd(TIM2,ENABLE);
}

void set_Zhankongbi(uint16_t  num)
{
	TIM_SetCompare1(TIM2,num);//通过改变CCR的值,从而改变CCR/CNT占空比
}

void set_PSC(uint16_t  num)
{
	TIM_PrescalerConfig(TIM2,num,TIM_PSCReloadMode_Immediate);//改变PSC的值
}	

/***************************************************/IC输入捕获模块
#include "stm32f10x.h"                  // Device header
#include "IC.h"

void IC_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打开TMI3,因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//**2.配置PWM输出引脚PA6
	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_InternalClockConfig(TIM3);
	//**3.配置时基单元
	//配置为1MHz
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
	TIM_TimeBaseInitStruct.TIM_Period=65536-1;//设置预装载值   ARR    //外部时钟的话用不了这么高的频率
	TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//设置预分频值   PSC
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM3,TIM_FLAG_Update);//初始化时会产生标志位,需要清除
	
	//**4.配置IC模块
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;//选择通道一
	TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;//选择上升沿触发
	TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择正极性
	TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;//选择一分频
	TIM_ICInitStruct.TIM_ICFilter=0xF;//选择滤波器的值
	TIM_ICInit(TIM3,&TIM_ICInitStruct);
	
	//**5.配置从模式
	TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
	
	//**6.使能定时器模块,开始计数
	TIM_Cmd(TIM3,ENABLE);
}

uint32_t get_Freq(void)
{
	return 1000000/(TIM_GetCapture1(TIM3)+1) ;
}


/***************************************************/主函数
int main(void)
{
	OLED_Init();
	pwm_init();
	IC_init();
	OLED_ShowString(1,1,"Hello,my honey");
	set_Zhankongbi(50);			//Freq = 72M / (PSC + 1) / 100
	set_PSC(720 - 1);			//Duty = CCR / 100
	while(1)
	{
		OLED_ShowNum(2,1,get_Freq(),5);
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/
5.2.2 PWMI模式同时测频率、占空比

相当于开了TI1FP2的通道去实现读取占空比

占空比是 CCR2记录的高电平持续时间 除以 CCR1记录的整个周期的时间

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "PWM.h"
#include "IC.h"

/***************************************************/PWM模块
#include "stm32f10x.h"                  // Device header


void pwm_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//**2.配置PWM输出引脚
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//**3.配置时基单元
	//配置为1000KHz,分辨率为1%
	TIM_InternalClockConfig(TIM2);//选择内部时钟源
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
	TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
	TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

	//**4.配置CCR
	TIM_OCInitTypeDef TIM_OCInitStruct;
	
	TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
	TIM_OCInitStruct.TIM_Pulse=0;//配置初始CCR计数器值
	TIM_OC1Init(TIM2,&TIM_OCInitStruct);
	
	//**5.开始计数
	TIM_Cmd(TIM2,ENABLE);
}

void set_Zhankongbi(uint16_t  num)
{
	TIM_SetCompare1(TIM2,num);//通过改变CCR的值,从而改变CCR/CNT占空比
}

void set_PSC(uint16_t  num)
{
	TIM_PrescalerConfig(TIM2,num,TIM_PSCReloadMode_Immediate);//改变PSC的值
}	

/***************************************************/IC输入捕获模块
#include "stm32f10x.h"                  // Device header
#include "IC.h"

void IC_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打开TMI3,因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//**2.配置PWM输出引脚PA6
	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_InternalClockConfig(TIM3);
	//**3.配置时基单元
	//配置为1MHz
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
	TIM_TimeBaseInitStruct.TIM_Period=65536-1;//设置预装载值   ARR    //外部时钟的话用不了这么高的频率
	TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//设置预分频值   PSC
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM3,TIM_FLAG_Update);//初始化时会产生标志位,需要清除
	
	//**4.配置IC模块
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;//选择通道一
	TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;//选择上升沿触发
	TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择正极性
	TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;//选择一分频
	TIM_ICInitStruct.TIM_ICFilter=0xF;//选择滤波器的值
	TIM_ICInit(TIM3,&TIM_ICInitStruct);
	TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);

	//**5.配置从模式
	TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
	TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
	
	//**6.使能定时器模块,开始计数
	TIM_Cmd(TIM3,ENABLE);
}

uint32_t get_Freq(void)
{
	return 1000000/(TIM_GetCapture1(TIM3)+1) ;
}

uint32_t get_Zhankongbi(void)
{
	return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
}
/***************************************************/主函数
int main(void)
{
	OLED_Init();
	pwm_init();
	IC_init();
	OLED_ShowString(1,1,"Hello,my honey");
	set_Zhankongbi(50);			//Freq = 72M / (PSC + 1) / 100
	set_PSC(720 - 1);			//Duty = CCR / 100
	while(1)
	{
		OLED_ShowNum(2,1,get_Freq(),5);
        OLED_ShowNum(3,1,get_Zhankongbi(),3);
	}
}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/
5.2.3 编码器接口测速(简介)

通过配置定时器,占用了IC捕获模式的两个通道,自动判断两个脚的波形相位差和边沿触发(一般都是使用T1T2模式,可消除毛刺信号

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Bianmaqi.h"
#include "Delay.h"
#include "timer2.h"

/***************************************************/延时函数
#include "Delay.h"
#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);
	}
} 

/***************************************************/编码器
#include "stm32f10x.h"                  // Device header
#include "Bianmaqi.h"

void Bianmaqi_init(void)
{
	//1**使能时钟
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA,ENABLE);
	
	//2**定义GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6 |GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	//3**初始化时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_Channel_1|TIM_Channel_2;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_Period=65536-1;
	TIM_TimeBaseInitStruct.TIM_Prescaler=1-1;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
	
	//4**初始化IC模块(部分)两个Pin口
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICStructInit(&TIM_ICInitStruct);
	TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
	TIM_ICInitStruct.TIM_ICFilter=0xF;
//	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_ICInitStruct.TIM_Channel=TIM_Channel_2;
	TIM_ICInitStruct.TIM_ICFilter=0xF;
//	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);
	
	//5**配置编码器
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Falling,TIM_ICPolarity_Rising);//控制极性
	
	//6.使能定时器TIM3
	TIM_Cmd(TIM3,ENABLE);
}

int16_t get_cnt(void)
{
	int16_t temp=0;
	temp=TIM_GetCounter(TIM3);
	TIM_SetCounter(TIM3,0);
	return temp;
}

/***************************************************/定时器TIM2
#include "stm32f10x.h"
#include "timer2.h"

extern int num;
void timer2_init(void)
{
	//**1.打开总的RCC,要配置GPIO从而传入外部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//**2.配置定时器接入外部时钟 同时配置外部时钟输入的引脚
	TIM_InternalClockConfig(TIM2);//设置定时器2使用内部时钟,可不写,上电默认
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	//TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//第二个设置分频,第三个设置触发方式,第四个设置采样频率(滤波器)
	//**3.配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上l计数
	TIM_TimeBaseInitStruct.TIM_Period=10000-1;//设置预装载值       //外部时钟的话用不了这么高的频率
	TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//设置预分频值
//	TIM_TimeBaseInitStruct.TIM_Period=10-1;//设置预装载值
//	TIM_TimeBaseInitStruct.TIM_Prescaler=2-1;//设置预分频值
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除
	//**4.使能时基单元的中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	//**5.配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组
	
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStruct);
	//**6.开始计数
	TIM_Cmd(TIM2,ENABLE);

}
/*
//配置中断函数
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		num++;
	}
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

}
*/

/***************************************************/主函数
int16_t speed=0;
int main(void)
{
	timer2_init();
	OLED_Init();
	Bianmaqi_init();
	OLED_ShowString(1,1,"Hello,my honey");
	while(1)
	{
		OLED_ShowSignedNum(2,1,speed,6);
	}
} 

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		speed=get_cnt();
		Delay_ms (10);
	}
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

}
/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

七、ADC模数转换

1.结构原理

1.1 介绍

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.2 原理

采样、抽取、量化、编码

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.3 ADC结构框图

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.4 stm32片上资源

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.5 ADC工作的4种模式

1.5.1 单次转换,非扫描模式

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.5.2 连续转换,非扫描模式

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.5.3 单次转换,扫描模式

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.5.4 连续转换,扫描模式 

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.6 ADC的触发方式(软件,硬件)

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

1.7 ADC的数据处理、转换时间、校准

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

2.代码配置

2.1 ADC单通道模式

单次转换、非连续模式

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "ADC.h"
#include "Delay.h"

/***************************************************/ADC模块
#include "stm32f10x.h"                  // Device header
#include "ADC.h"


void ADC_init(void)
{
	//1.先使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//2.设置ADC的分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	//3.配置GPIO口PA0
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	//4.确定规则组或注入组的通道
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_28Cycles5);
	
	//5.初始化ADC
	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//配置是否连续触发模式
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//选择数据对齐模式为右对齐
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//选择外界触发源
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//配置是ADC是几个同时工作还是独立工作
	ADC_InitStruct.ADC_NbrOfChannel=1;//确定要输入的组的个数
	ADC_InitStruct.ADC_ScanConvMode=DISABLE;//是否连续扫描模式
	ADC_Init(ADC1, &ADC_InitStruct);
	
	//6.打开ADC
	ADC_Cmd(ADC1,ENABLE);
	
	//7.校准ADC
	ADC_ResetCalibration(ADC1);//1.复位校准
	while(ADC_GetResetCalibrationStatus(ADC1));//2.等待复位校准完成
	ADC_StartCalibration(ADC1);//3.开始校准
	while(ADC_GetCalibrationStatus(ADC1));//4.等待校准完成
}

uint16_t get_adcvalue(void)
{
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//触发开始ADC读值
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//读取EOC标志位,当转化读取完成后退出循环
	return ADC_GetConversionValue(ADC1);//读取ADC寄存器,自动清除EOC标志位
}

/***************************************************/延时函数
#include "Delay.h"
#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);
	}
} 

/***************************************************/主函数

uint16_t ADCvalue;//旋钮值
float  Voltage;//转换成电压值
int main(void)
{
	OLED_Init();
	ADC_init();
	OLED_ShowString(1,1,"Hello,my honey");

	OLED_ShowString(2, 1, "ADValue:");
	OLED_ShowString(3, 1, "Volatge:0.00V");
	while(1)
	{
		ADCvalue=get_adcvalue();
		Voltage = (float)ADCvalue / 4095 * 3.3;
		
		OLED_ShowNum(2, 9, ADCvalue, 4);
		OLED_ShowNum(3, 9, Voltage, 1);//这里将电压值按整数部分和小数部分两部分取出来
		OLED_ShowNum(3, 11, (uint16_t)(Voltage * 100) % 100, 2);
		
		Delay_ms(100);;
	}
}


/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

**2.简单实现ADC多通道

每次改变序号里的通道即可;

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "ADC.h"
#include "Delay.h"

/***************************************************/ADC
#include "stm32f10x.h"                  // Device header
#include "ADC.h"


void ADC_init(void)
{
	//1.先使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//2.设置ADC的分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	//3.配置GPIO口PA0
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	//4.确定规则组或注入组的通道
//	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_28Cycles5);
	
	//5.初始化ADC
	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//配置是否连续触发模式
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//选择数据对齐模式为右对齐
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//选择外界触发源
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//配置是ADC是几个同时工作还是独立工作
	ADC_InitStruct.ADC_NbrOfChannel=1;//确定要输入的组的个数
	ADC_InitStruct.ADC_ScanConvMode=DISABLE;//是否连续扫描模式
	ADC_Init(ADC1, &ADC_InitStruct);
	
	//6.打开ADC
	ADC_Cmd(ADC1,ENABLE);
	
	//7.校准ADC
	ADC_ResetCalibration(ADC1);//1.复位校准
	while(ADC_GetResetCalibrationStatus(ADC1));//2.等待复位校准完成
	ADC_StartCalibration(ADC1);//3.开始校准
	while(ADC_GetCalibrationStatus(ADC1));//4.等待校准完成
}

uint16_t get_adcvalue(uint8_t ADC_Channel)
{
		ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_28Cycles5);

	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//触发开始ADC读值
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//读取EOC标志位,当转化读取完成后退出循环
	return ADC_GetConversionValue(ADC1);//读取ADC寄存器,自动清除EOC标志位
}
     
/***************************************************/延时
#include "Delay.h"
#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);
	}
} 

/***************************************************/主函数
uint16_t key,light;

int main(void)
{
	OLED_Init();
	ADC_init();
	OLED_ShowString(1,1,"Hello,my honey");
//	OLED_ShowString(2,1,"Hello WangFang");
//	OLED_ShowString(3,1,"Hello Tomorrow");
//	OLED_ShowString(4,1,"I miss you");

	while(1)
	{
		key=get_adcvalue(ADC_Channel_0);
		light=get_adcvalue(ADC_Channel_1);
		
		OLED_ShowNum(2,1,key,5);
		OLED_ShowNum(3,1,light,5);
	}
}

/*********************阿布君***********************/
/****************编码不易,谢谢关注*****************/
/****************QQ:2062808868********************/

3.DMA实现数据迁移

**1.结构原理

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

stm32f103c8t6的启动文件,stm32,笔记,单片机,嵌入式硬件,c语言

待续

8.USART串口

1.文章来源地址https://www.toymoban.com/news/detail-779502.html

到了这里,关于stm32(F103c8t6)自学笔记@阿布君的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32 F103C8T6学习笔记4:时钟树、滴答计时器、定时器定时中断

    今日理解一下STM32F103 C8T6的时钟与时钟系统、滴答计时器、定时器计时中断的配置,文章提供原理,代码,测试工程下载。 目录 时钟树与时钟系统: 滴答计时器: 定时器计时中断: 测试结果: 测试工程下载: 该系统介绍在 STM32F10x-中文参考手册 P56页开始 微控制器的时钟系

    2024年02月13日
    浏览(13)
  • STM32 F103C8T6学习笔记8:0.96寸单色OLED显示屏显示字符

    使用STM32F103 C8T6 驱动0.96寸单色OLED显示屏: OLED显示屏的驱动,在设计开发中OLED显示屏十分常见,因此今日学习一下。一篇文章从程序到显示都讲通。 文章提供源码、原理解释、测试工程下载,测试效果图展示。   目录 OLED驱动原理—IIC通信: SSD1306 单色 0.96 OLED 显示屏特性

    2024年02月12日
    浏览(18)
  • STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块

    今日学习一下这款AHT10 温湿度传感器模块,给我的OLED手环添加上测温湿度的功能。 文章提供源码、测试工程下载、测试效果图。 目录 AHT10温湿度传感器: 特性: 连接方式: 适用场所范围: 程序设计: 设计目标:  程序设计注意点: AHT10代码:  主函数代码: 测试效果:

    2024年02月11日
    浏览(17)
  • STM32 F103C8T6学习笔记2:GPIO的认识—GPIO的基本输入输出—点亮一个LED

    今日继续学习使用  STM32 F103C8T6开发板 点亮一个LED灯,文章提供源码,测试工程,实验效果图,希望我的归纳总结会对大家有帮助~ 目录 GPIO的认识与分类 : 引脚安排整理: 定时器的引脚例举: 串口的引脚例举:  CAN串口通信: SPI通信: IIC通信:  其余引脚: 烧录引脚:

    2024年02月11日
    浏览(18)
  • STM32 F103C8T6学习笔记5:定时器输出不同占空比PWM驱动舵机旋转角度

    现在学习使用STM32 F103C8T6的定时器PWM模式,使用PWM驱动舵机转动不同角度,文章提供源码,测试工程,测试动态效果图。 目录 基础原理:  实验目标: 测试视频结果: 测试工程下载: 这次依旧拿出之前学习过的舵机DS3115,它的基础原理不多加介绍,在往期讲MSP432的文章有所

    2024年02月13日
    浏览(17)
  • STM32 HAL库 CubeMX配置 定时器学习 F103C8T6

    开发板: STM32F103C8T6最小系统板 编译环境: Keil5 MDK 辅助软件: STM32 CubeMX 课程教学: 基于正点原子HAL库学习教程 其余配件: 江科大STM32配件包 和 示波器一台 备注:  因为这块开发板没有基本定时器,所以本文也 没有基本定时器的内容             本文1.3和2.1部分的

    2024年04月26日
    浏览(12)
  • STM32 F103C8T6学习笔记10:OLED显示屏GIF动图取模—简易时钟—动图手表的制作~

    今日尝试做一款有动图的OLED实时时钟,本文需要现学一个OLED的GIF动图取模 其余需要的知识点有不会的可以去我  STM32 F103C8T6学习笔记  系列专栏自己查阅把,闲话不多,直接开肝~~~ 文章提供源码,测试工程下载,测试效果图。 做个简易的时钟,就不把RTC实时时钟放进来学了

    2024年02月12日
    浏览(16)
  • STM32 F103C8T6学习笔记6:IIC通信__驱动MPU6050 6轴运动处理组件—一阶互补滤波

    今日主要学习一款倾角传感器——MPU6050,往后对单片机原理基础讲的会比较少,更倾向于简单粗暴地贴代码,因为经过前些日子对MSP432的学习,对原理方面也有些熟络了,除了在新接触它时会对其引脚、时钟、总线等进行仔细一些的研究之外,其余驱动方面便是照搬经验了~

    2024年02月13日
    浏览(19)
  • STM32 F103C8T6学习笔记9:0.96寸单色OLED显示屏—自由取模显示—显示汉字与图片

    今日学习0.96寸单色OLED显示屏的自由取模显示: 宋体汉字比较复杂,常用字符可以直接复制存下来,毕竟只有那么几十个字母字符,但汉字实在太多了,基本不会全部放在单片机里存着,一般用到多少个字就取几个字的模,因此汉字放在这里与自由取模一起讲。 文章提供源码

    2024年02月11日
    浏览(18)
  • STM32系列(HAL库)——F103C8T6获取DHT11温湿度串口打印

    在此特别鸣谢原文博主! (1)编程平台:Keil5 (2)CubeMX (3)XCOM(串口调试助手) (1)F1的板子,本例使用经典F103C8T6  (2)DHT11——温湿度传感器 (3)ST-link 下载器 (4)USB-TTL模块 (5)杜邦线若干 (1)芯片选择 STM32F103C8T6  (2)配置RCC、SYS、时钟树 配置RCC 配置SYS 配置时钟树 (3) 配置GPIO  (4)配置

    2023年04月08日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包