STM32开发笔记
MDK5小技巧:按ctrl+空格可以自动补全;
1.PWM控制LED呼吸灯效果
外设时钟配置
void Rcc_config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);//使能GPIOB 时钟和功能复用 IO 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//使能TIM2 时钟
}
GPIO配置
void Gpio_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
定时器配置
void Tim_config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 500;//计数长度为19999+1=20000,可得PWM频率为1M/20000=50Hz
TIM_TimeBaseStructure.TIM_Prescaler = 72;//系统默认时钟为72MHz,预分频71+1次,得到TIM3计数时钟为1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置了时钟分割,TIM_CKD_DIV1为分割;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
//TIM向上计数模式
// TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure);
GPIO_PinRemapConfig(GPIO_PartialRemap2_TIM2,ENABLE); //改变指定管脚的映射???
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//选择定时器模式:TIM脉冲宽度调制模式1
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//比较输出使能
// TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Enable;
//使能输出比较 N 状态
TIM_OCInitStructure.TIM_Pulse=250;//设置了待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出极性:TIM输出比较极性高
// TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;
// TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset;
// TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCIdleState_Reset;
TIM_OC3Init(TIM2,&TIM_OCInitStructure);//使能TIMx在CCR2上的预装载寄存器,OCx确定了是channlex,要是OC3则是channel 3
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);//使能TIMx在ARR上的预装载寄存器
//TIM_CtrlPWMOutputs(TIM2,ENABLE);//设置TIM2的PWM输出为使能
TIM_Cmd(TIM2,ENABLE);//使能TIMx外设
}
延迟函数
void delayms(u32 i)
{
u32 temp;
SysTick->LOAD=9000*i;
SysTick->CTRL=0X01;
SysTick->VAL=0X00;
do
{
temp=SysTick->CTRL;
}
while((temp&0x01)&&(!(temp&(1<<16))));
SysTick->CTRL=0X00;
SysTick->VAL=0X00;
}
主函数
int main(void)
{
u16 i;
Rcc_config();
Gpio_config();
Tim_config();
while(1)
{
for(i=0;i<300;i++)
{
TIM_SetCompare3(TIM2, i);//设置 TIMx 捕获比较 3 寄存器值 channelx x是几TIM_SetComparex x是几;
delayms(10);
}
}
}
颜色传感器调
51部分:
波特率计算公式:TH1=256-(Fsoc×2smod)/(12×32×Baud)
Fsoc:晶振频率,单位HZ
SMOD:波特率加倍smod=1,不加倍smod=0;
Baud:波特率
机器周期 = 12*时钟周期=12/晶振频率(MHZ)us 12M晶振机械周期为1us
计数初值高8位(TH1)=(满计数值-定时时间/机械周期)/256;
计数初值低8位(TL1)=(满计数值-定时时间/机械周期)%256;
.
下面给出52定时器2的串口波特率初始化函数:
.
void Uart0_Init()
.
{
.
RCAP2L=0xD9;//9600波特率对应 FFD9,低位为D9
.
RCAP2H=0xFF;//高位为FF
.
T2CON=0x34;//RCLK、TCLK、TR2置1
.
SCON=0x50;//串口工作模式1,接收使能
.
ES=1;//打开接收中断
.
EA=1;//打开总中断
.
}
.
.
5
.
中断函数:
.
void Uart0_Ist() interrupt 4 //中断函数
.
{
.
if(RI)
.
{
.
RI= 0;
.
//Do whatever you want;
.
}
.
if(TI)
.
{
.
TI = 0;
.
//Do whatever you want;
.
}
.
}
STM32部分:
int main(void)
{
RCC_config();
Gpio_config();
TIM2_config();
TIM3_config();
uart1_init();
nvid_init();
while(1)
{
}
STM32串口通讯
串口1配置:
#ifndef _CONFIG_H
#define _CONFIG_H
#include
void sys_init(void);
void gpio_init(void);
void uart1_init(void);
void nvid_init(void);
void USART1_IRQHandler(void);
#endif
#include"config.h"
void sys_init(void)
{
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
}
void gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void uart1_init(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
USART_ClearFlag(USART1,USART_FLAG_RXNE|USART_FLAG_TC|USART_FLAG_TXE);
}
void nvid_init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART1_IRQHandler(void)
{
u8 k;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//检查指定的USART中断发生与否
{
k=USART_ReceiveData(USART1);
USART_SendData(USART1,k);//通过外设USARTx发送单个数据
//USART_ReceiveData(USART1)返回USARTx最近接收到的数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}
}
#include"config.h"
int main(void)
{
sys_init();
gpio_init();
uart1_init();
nvid_init();
while(1);
}
串口2配置:
int main()
{
RCCINIT(); //系统时钟的初始化
GPIOINIT(); // 端口的初始化
USARTINIT(); // 串口的配置及其初始化
NVICINIT(); // 中断模式的初始化
while(1);
}
void RCCINIT() //系统时钟的初始化配置
{
SystemInit();//72m
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
}
void GPIOINIT() //端口的初始化配置
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;//TX
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;//RX
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
}
void USARTINIT() //通讯串口的配置
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate=9600; //波特率设置为9600
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART2,&USART_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//使能或者失能指定的USART中断 接收中断
USART_ClearFlag(USART2,USART_FLAG_TC);//清除USARTx的待处理标志位
}
void NVICINIT() //中断模式的配置
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART2_IRQHandler(void)
{
u8 k;
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)//检查指定的USART中断发生与否
{
k=USART_ReceiveData(USART2);
k++;
USART_SendData(USART2,k);//通过外设USARTx发送单个数据
//USART_ReceiveData(USART1)返回USARTx最近接收到的数据
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
}
}
STM32串口printf打印配置
注意:要加入stdio.h头文件
1.RCC配置:
void ADC_RCC_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1|RCC_APB2Periph_USART1, ENABLE);
}
2.Gpio配置:
void uart1_Gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = Uart1_Txd;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = Uart1_Rxd;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
3.uart1初始化:
void uart1_init(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
USART_ClearFlag(USART1,USART_FLAG_RXNE|USART_FLAG_TC|USART_FLAG_TXE);
USART_Cmd(USART1, ENABLE);
}
4.串口中断初始化:
void nvic_uart1(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
5.输入输出初始化函数:
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
/// 重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
/* 等待串口1输入数据 */
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
STM32定时器2控制led
Tout= ((999+1)*(71+1))/Tclk;
其中:
TIM_Period: 999(1000-1) 定时周期为1000
TIM_Prescaler:71(72-1) 分频系数72
Tclk: TIM1 的输入时钟频率(单位为 Mhz)。
Tout: TIM1 溢出时间(单位为 us)。
这里我们设置溢出时间为: 72000/72M = 1000us = 1ms
注意:每次进入中断服务程序间隔时间为
((1+TIM_Prescaler )/72M)*(1+TIM_Period )=((1+7199)/72M)*(1+9999)=1秒*/
TIM_Prescaler://分频35999 72000k/(35999+1)/2=1Hz 1秒中断溢出一次
TIM_Period://计数次数TIM_Period=秒/((1+TIM_Prescaler )/72000000)-1;
由上式得:
1.SYSTEM CLOCK CONFIG;(RCC)//在main函数中必须先调用RCC再调用别的函数;
2.LED GPIO CONFIG;
3.NVIC CONFIG;
4.TIMX CONFIG;
5.TIMX HANDLER FUNCTION;
#include
/*1.LED GPIO CONFIG;*/
void Gpio_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*2.SYSTEM CLOCK CONFIG;(RCC)*/
void Sys_config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//GPIOB CLOCK OPENED;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//TIM3 CLOCK OPENED;
}
/*3.NVIC CONFIG;*/
void Nvic_config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*4.TIMX CONFIG;*/
void Tim3_config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除 TIMx 的中断待处理位
TIM_TimeBaseStructure.TIM_Period = 1000;
TIM_TimeBaseStructure.TIM_Prescaler = 35999;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, & TIM_TimeBaseStructure);
TIM_Cmd(TIM3, ENABLE);//使能或者失能 TIMx 外设
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//使能或者失能指定的 TIM 中断
}
#include
void TIM3_IRQHandler(void)
{
u8 ReadValue;
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除 TIMx 的中断待处理位
ReadValue = GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_8);
if(ReadValue==Bit_RESET) GPIO_SetBits(GPIOB,GPIO_Pin_8);
else GPIO_ResetBits(GPIOB,GPIO_Pin_8);
}
int main(void)
{
Sys_config();
Gpio_config();
Tim3_config();
Nvic_config();
while(1);
}
STM32计数器
第一步,设置RCC
第二步:设置GPIO
第三步,设置定时器模式
第四步,可以在主函数中读取计数器的值,其它的应用,就看具体的情况了。
STM32超声波模块
1.系统时钟RCC初始化
2.GPIO初始化
3.定时器初始化
Tout= ((999+1)*(71+1))/Tclk;
其中:
TIM_Period: 999(1000-1) 定时周期为1000系统时钟振荡1000次,一次1us;
TIM_Prescaler:71(72-1) 分频系数72
Tclk: TIM1 的输入时钟频率(单位为 Mhz)。
Tout: TIM1 溢出时间(单位为 us)。
这里我们设置溢出时间为: 72000/72M = 1000us = 1ms
4.定时器中断初始化
5.中断函数作用
6.超声波距离测试算法:
1.先使用STM32的数字引脚向TRIG脚输入至少10us的高电平信号,触发模块的测距功能。然后将管脚拉低;
测距功能触发后,模块将自动发出 8 个 40kHz 的超声波脉冲,并自动检测是否有信号返回,这一步由模块内部自动完成。
2.一旦检测到有回波信号则ECHO引脚会输出高电平。高电平持续的时间就是超声波从发射到返回的时间。此时可以使用定时器获取高电平的时间, 并计算出距被测物体的实际距离。公式: 距离=高电平时间*声速(340M/S)/2;
7.主函数使用
#include "config.h"
#ifdef ultrasonic
void Ultrasonic_init(void)
{
Rcc_init();
Gpio_init();
TIM2_init();
uart1_init();
NVIC_init();
nvic_uart1();
}
void Ultrasonic_Enable(void)
{
printf("%d\n",Distance_test());
}
void Rcc_init(void)
{
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_USART1,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
}
void Gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
GPIO_InitStructure.GPIO_Pin = Echo;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = Trig;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = Uart1_Txd;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = Uart1_Rxd;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// /**debug**/
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
// GPIO_Init(GPIOB, &GPIO_InitStructure);
//
// GPIO_ResetBits(GPIOB,GPIO_Pin_15);
}
void TIM2_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Period = 999;
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
TIM_Cmd(TIM2,DISABLE);
}
void NVIC_init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM2, TIM_IT_Update ,ENABLE);
}
void delayus(u32 i)
{
u32 temp;
SysTick->LOAD=9*i; //设置重装数值, 72MHZ时
SysTick->CTRL=0X01; //使能,减到零是无动作,采用外部时钟源
SysTick->VAL=0; //清零计数器
do
{
temp=SysTick->CTRL; //读取当前倒计数值
}
while((temp&0x01)&&(!(temp&(1<<16)))); //等待时间到达
SysTick->CTRL=0; //关闭计数器
SysTick->VAL=0; //清空计数器
}
u16 Distance_test(void)
{
u16 i;
for(i=0;i<5;i++)
{
GPIO_SetBits(GPIOA,Trig);
delayus(20);
GPIO_ResetBits(GPIOA,Trig);
while(GPIO_ReadInputDataBit(GPIOA, Echo)==RESET);
TIM_Cmd(TIM2,ENABLE);
while(GPIO_ReadInputDataBit(GPIOA,Echo)==SET);
TIM_Cmd(TIM2,DISABLE);
count=TIM_GetCounter(TIM2);
Sum+=((count+overtime*1000)/58.0)-3;
TIM_SetCounter(TIM2,0);
overtime=0;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
Sum /= 5;
return Sum;
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
overtime++;
}
}
#endif
#ifdef Uart1_print
/*uart1_init*/
void uart1_init(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
USART_ClearFlag(USART1,USART_FLAG_RXNE|USART_FLAG_TC|USART_FLAG_TXE);
USART_Cmd(USART1, ENABLE);
}
void nvic_uart1(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
/// 重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
/* 等待串口1输入数据 */
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
#endif
STM32 ADC转换器
1.开启 PA 口时钟和 ADC1 时钟,设置 PA0 为模拟输入。使能 GPIOA 和 ADC 时钟用 RCC_APB2PeriphClockCmd 函数,设置 PA0 的输入方式,使用 GPIO_Init 函数即可。
2. 复位 ADC1,同时设置 ADC1 分频因子。
参数 ADC_Mode 故名是以是用来设置 ADC 的模式。前面讲解过, ADC 的模式非常多,包括独立模式,注入同步模式等等,这里我们选择独立模式,所以参数为 ADC_Mode_Independent。参数 ADC_ScanConvMode 用来设置是否开启扫描模式, 因为是单次转换,这里我们选择不开启值 DISABLE 即可。参数ADC_ContinuousConvMode 用来设置是否开启连续转换模式,因为是单次转换模式,所以我们选择不开启连续转换模式, DISABLE 即可。
参数 ADC_ExternalTrigConv 是用来设置启动规则转换组转换的外部事件,这里我们选择软件触发,选择值为 ADC_ExternalTrigConv_None 即可。参数 DataAlign 用来设置 ADC 数据对齐方式是左对齐还是右对齐,这里我们选择右对齐方式ADC_DataAlign_Right。参数 ADC_NbrOfChannel 用来设置规则序列的长度,这里我们是单次转换,所以值为 1 即可。
通过上面对每个参数的讲解, 下面来看看我们的初始化范例:
ADC 时钟复位的方法是:
ADC_DeInit(ADC1);
分频因子:
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//这个我们设置分频因子位 6, 时钟为 72/6=12MHz,
3.初始化 ADC1 参数, 设置 ADC1 的工作模式以及规则序列的相关信息。
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC 工作模式:独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //AD 单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //AD 单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
//转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的 ADC 通道的数目 1
ADC_Init(ADC1, &ADC_InitStructure); //根据指定的参数初始化外设 ADCx
4.使能 ADC 并校准。
在设置完了以上信息后, 我们就使能 AD 转换器,执行复位校准和 AD 校准,注意这两步是必须的!不校准将导致结果很不准确。
使能指定的 ADC 的方法是:
ADC_Cmd(ADC1, ENABLE); //使能指定的 ADC1
执行复位校准的方法是:
ADC_ResetCalibration(ADC1);
执行 ADC 校准的方法是:
ADC_StartCalibration(ADC1); //开始指定 ADC1 的校准状态
记住,每次进行校准之后要等待校准结束。 这里是通过获取校准状态来判断是否校准是否结束。下面我们一一列出复位校准和 AD 校准的等待结束方法:
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
while(ADC_GetCalibrationStatus(ADC1)); //等待校 AD 准结束
5.读取 ADC 值。
在上面的校准完成之后,ADC 就算准备好了。接下来我们要做的就是设置规则序列 1 里面的通道,采样顺序, 以及通道的采样周期, 然后启动 ADC 转换。在转换结束后,读取 ADC 转换结果值就是了。 这里设置规则序列通道以及采样周期的函数是:
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel,
uint8_t Rank, uint8_t ADC_SampleTime);
我们这里是规则序列中的第 1 个转换,同时采样周期为 239.5,所以设置为:
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
软件开启 ADC 转换的方法是:
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的 ADC1 的软件转换启动功能开启转换之后,就可以获取转换 ADC 转换结果数据, 方法是:
ADC_GetConversionValue(ADC1);
同时在 AD 转换中,我们还要根据状态寄存器的标志位来获取 AD 转换的各个状态信息。 库函数获取 AD 转换的状态信息的函数是:
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG)
比如我们要判断 ADC1d 的转换是否结束,方法是:
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
这里还需要说明一下 ADC 的参考电压,战舰 STM32 开发板使用的是 STM32F103C8T6,该芯片有外部参考电压: Vref-和 Vref+,其中 Vref-必须和 VSSA 连接在一起, 而 Vref+的输入范围为: 2.4~VDDA。如果大家想自己设置其他参考电压,将你的参考电压接在 Vref-和 Vref+上就 OK 了。本章我们的参考电压设置的是 3.3V。
通过以上几个步骤的设置,我们就能正常的使用 STM32 的 ADC1 来执行 AD 转换操作了。
简单总结:
1.RCC配置;
void ADC_RCC_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1|RCC_APB2Periph_USART1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//6分频,72M/6=12M;
}
2.GPIO配置为GPIO_Mode_AIN; //模拟输入
void ADC_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
3. ADC配置;
void ADC_init(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1,ADC_SampleTime_239Cycles5);//使能或者失能指定的 ADC 规则组通道的间断模式
ADC_Cmd(ADC1, ENABLE);//使能或者失能指定的 ADC
ADC_ResetCalibration(ADC1);//重置指定的 ADC 的校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//获取 ADC 重置校准寄存器的状态
ADC_StartCalibration(ADC1);//开始指定 ADC 的校准状态
while(ADC_GetCalibrationStatus(ADC1));//获取指定 ADC 的校准程序
//ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
4.main函数读取ADC的值
while(1)
{
for(i=0;i<50;i++)//读取50次的AD数值取其平均数较为准确
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能 ADC 的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//检查制定 ADC 标志位置 1 与否
Conversion_value+=ADC_GetConversionValue(ADC1);//返回最近一次 ADC1 规则组的转换结果
}
Conversion_value /=50;//计数50次取平均值;
printf("%f",Conversion_value*3.3/4096);
}
}
ADC读取芯片电压
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include
#include
#define ADC_conversion
#define Uart1_print
#define Uart1_Txd GPIO_Pin_9
#define Uart1_Rxd GPIO_Pin_10
void ADC_RCC_Config(void);
void ADC_GPIO_Config(void);
void uart1_Gpio_init(void);
void ADC_init(void);
void uart1_init(void);
void nvic_uart1(void);
int fputc(int ch, FILE *f);
int fgetc(FILE *f);
#endif
#include "Config.h"
#ifdef ADC_conversion
void ADC_RCC_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1|RCC_APB2Periph_USART1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
}
void ADC_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void ADC_init(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1,ADC_SampleTime_239Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
//ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
#endif
#ifdef Uart1_print
void uart1_Gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = Uart1_Txd;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = Uart1_Rxd;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*uart1_init*/
void uart1_init(void)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);
USART_ClearFlag(USART1,USART_FLAG_RXNE|USART_FLAG_TC|USART_FLAG_TXE);
USART_Cmd(USART1, ENABLE);
}
void nvic_uart1(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
/// 重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
/* 等待串口1输入数据 */
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
#endif
Main:
#include "Config.h"
int main(void)
{
int i;
double Conversion_value;
ADC_RCC_Config();
ADC_GPIO_Config();
uart1_Gpio_init();
ADC_init();
uart1_init();
nvic_uart1();
while(1)
{
for(i=0;i<50;i++)//读取50次的AD数值取其平均数较为准确
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能 ADC 的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//检查制定 ADC 标志位置 1 与否
Conversion_value+=ADC_GetConversionValue(ADC1);//返回最近一次 ADC1 规则组的转换结果
}
Conversion_value /=50;//计数50次取平均值;
printf("%f",Conversion_value*3.3/4096);
}
}
SPI配置
spi2为主机 spi1为从机:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能spi1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//使能spi2
配置spi接口对应的gpio口:
//spi从机
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;//sck mosi
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//miso
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//cs
GPIO_Init(GPIOA,&GPIO_InitStructure);
//spi主机
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽复用
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_15;//sck mosi
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;//miso
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//cs
GPIO_Init(GPIOB,&GPIO_InitStructure);
spi口配置:
void SPI1_conf(void)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_Cmd(SPI1, DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
/*Enable SPI1.NSS as a GPIO*/
//SPI_SSOutputCmd(SPI1, ENABLE);
SPI_Cmd(SPI1, ENABLE);
//spi1_cs_low;
}
void SPI2_conf(void)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_Cmd(SPI2, DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);
}
SPI读写数据:
u8 SPIWriteByte(u8 Byte)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //等待发送区空
SPI_I2S_SendData(SPI2, Byte); //发送一个byte
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //等待接收完一个byte
return SPI_I2S_ReceiveData(SPI1); //返回收到的数据
}