[mw_shl_code=c,true]/*
*********************************************************************************************************
* Embedded Systems Building Blocks
* Complete and Ready-to-Use Modules in C
*
* TIMER Module Driver
*
* (c) Copyright 2014, Fisher
*
* Filename : timer.c
* Programmer : Fisher
*********************************************************************************************************
* DESCRIPTION
*
* 这个模块提供各个定时器的初始化接口,以及定时器的中断服务程序
*
* 消耗的IO口:PA11 下拉输入,作为TIM1的通道四输入捕获口
* PA1 下拉输入,作为TIM2的通道二输入捕获口
* PA0 下拉输出,作为超声波模块的触发信号,在定时器1中断中
*********************************************************************************************************
*/
/*$PAGE*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#include "timer.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
/*$PAGE*/
/*
*********************************************************************************************************
* CONSTANTS
*********************************************************************************************************
*/
/*
** 捕获状态
** [7]:0,没有成功的捕获;1,成功捕获到一次.
** [6]:0,还没捕获到高电平;1,已经捕获到高电平了.
** [5:0]:捕获高电平后溢出的次数
*/
u8 TIM1CH4_CAPTURE_STA = 0; /* 输入捕获状态 */
u16 TIM1CH4_CAPTURE_VAL; /* 输入捕获值 */
u8 TIM2CH2_CAPTURE_STA = 0; /* 输入捕获状态 */
u16 TIM2CH2_CAPTURE_VAL; /* 输入捕获值 */
float high = 0.0;
/*$PAGE*/
/*
*********************************************************************************************************
* 定时器1中断服务程序
*
* 描述: 此函数提供定时器3的中断服务程序
* 参数: 无
* 返回值:无
*********************************************************************************************************
*/
void TIM1_UP_IRQHandler(void)
{
if(TIM1->SR & 0X0001) /* 溢出中断 */
{
/* 中断处理程序 */
LED_GRE = !LED_GRE;
PAout(0) = 1; /* 脉冲触发 */
delay_us(10); /* 手册中需要至少给10us的高电平脉冲 */
PAout(0) = 0;
}
TIM1->SR &= ~(1 << 0); /* 清除中断标志位 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 初始化定时器输入捕获功能
*
* 描述: 此函数初始化STM32定时器1的输入捕获功能
* Tout = ((arr+1) * (psc+1))/ Tclk
* 参数: arr 自动重装值。
* psc 时钟预分频数
* 返回值:无
*********************************************************************************************************
*/
void TIM1_Cap_Init(u16 arr,u16 psc)
{
RCC->APB2ENR |= 1 << 11; /* TIM1时钟使能 */
RCC->APB1ENR |= 1 << 2; /* GPIOA 时钟使能 */
GPIOA->CRH &= 0XFFFF0FFF;
GPIOA->CRH |= 0X00008000; /* PA11下拉输入 */
GPIOA->ODR |= 0 << 11;
/*
** 自动重装载值,计数器计数到这个值就会触发溢出中断
*/
TIM1->ARR = arr;
/*
** 预分频器,得到计数时钟,
** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s
*/
TIM1->

SC = psc;
TIM1->CCMR2 |= 1 << 8; /* CC4S = 01, CC4通道配置为输入,IC4映射到TI4上 */
TIM1->CCMR2 |= 0 << 12; /* IC4F=0000 配置输入滤波器 不滤波 */
TIM1->CCMR2 |= 0 << 10; /* IC4PS=00 配置输入分频,不分频 */
TIM1->CCER |= 0 << 13; /* CC4P=0 上升沿捕获 */
TIM1->CCER |= 1 << 12; /* CC4E=1 允许捕获计数器的值到捕获寄存器中 */
/* 这两个东东要同时设置才可以使用中断 */
TIM1->DIER |= 1 << 0; /* 允许更新中断 */
TIM1->DIER |= 1 << 4; /* 允许捕获4中断 */
TIM1->CR1 |= 0x01; /* 使能定时器1 */
MY_NVIC_Init(1,0,TIM1_UP_IRQChannel,1); /* 抢占1,子优先级2,组1 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 初始化定时器输入捕获功能
*
* 描述: 此函数初始化STM32定时器2的输入捕获功能
* Tout = ((arr+1) * (psc+1))/ Tclk
* 参数: arr 自动重装值。
* psc 时钟预分频数
* 返回值:无
*********************************************************************************************************
*/
void TIM2_Cap_Init(u16 arr,u16 psc)
{
RCC->APB1ENR |= 1 << 0; /* TIM2时钟使能 */
RCC->APB2ENR |= 1 << 2; /* GPIOA 时钟使能 */
GPIOA->CRL &= 0XFFFFFF0F;
GPIOA->CRL |= 0X00000080; /* PA1下拉输入 */
GPIOA->ODR |= 0 << 1;
/*
** 自动重装载值,计数器计数到这个值就会触发溢出中断
*/
TIM2->ARR = arr;
/*
** 预分频器,得到计数时钟,
** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s
*/
TIM2->

SC = psc;
TIM2->CCMR1 |= 1 << 8; /* CC2S = 01, CC2通道配置为输入,IC2映射到TI2上 */
TIM2->CCMR1 |= 0 << 12; /* IC2F=0000 配置输入滤波器 不滤波 */
TIM2->CCMR1 |= 0 << 10; /* IC2PS=00 配置输入分频,不分频 */
TIM2->CCER |= 0 << 5; /* CC2P=0 上升沿捕获 */
TIM2->CCER |= 1 << 4; /* CC2E=1 允许捕获计数器的值到捕获寄存器中 */
/* 这两个东东要同时设置才可以使用中断 */
TIM2->DIER |= 1 << 0; /* 允许更新中断 */
TIM2->DIER |= 1 << 2; /* 允许捕获2中断 */
TIM2->CR1 |= 0x01; /* 使能定时器2 */
MY_NVIC_Init(2,2,TIM2_IRQChannel,2); /* 抢占2,子优先级2,组2 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 初始化定时器1
*
* 描述: 此函数初始化STM32定时器1
* Tout = ((arr+1) * (psc+1))/ Tclk
* 参数: arr 自动重装值。
* psc 时钟预分频数
* 返回值:无
*********************************************************************************************************
*/
void Timer1_Init(u16 arr,u16 psc)
{
RCC->APB2ENR |= 1 << 11; /* TIM1时钟使能 */
/*
** 自动重装载值,计数器计数到这个值就会触发溢出中断
*/
TIM1->ARR = arr;
/*
** 预分频器,得到计数时钟,
** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s
*/
TIM1->

SC = psc;
/* 这两个东东要同时设置才可以使用中断 */
TIM1->DIER |= 1 << 0; /* 允许更新中断 */
TIM1->DIER |= 1 << 6; /* 允许触发中断 */
TIM1->CR1 |= 0x01; /* 使能定时器4 */
MY_NVIC_Init(2,1,TIM1_UP_IRQChannel,2); /* 抢占2,子优先级1,组2 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 定时器2中断服务程序
*
* 描述: 此函数提供定时器3的中断服务程序
* 参数: 无
* 返回值:无
*********************************************************************************************************
*/
void TIM2_IRQHandler(void)
{
u16 tsr;
tsr = TIM2->SR;
if((TIM2CH2_CAPTURE_STA & 0X80) == 0) /* 还未成功捕获 */
{
if(tsr & 0X01) /* 溢出 */
{
if(TIM2CH2_CAPTURE_STA & 0X40) /* 已经捕获到高电平了 */
{
if((TIM2CH2_CAPTURE_STA & 0X3F) == 0X3F) /* 高电平太长了 */
{
TIM2CH2_CAPTURE_STA |= 0X80; /* 标记成功捕获了一次 */
TIM2CH2_CAPTURE_VAL = 0XFFFF;
} else TIM2CH2_CAPTURE_STA++;
}
}
if(tsr & (1 << 2)) /* 捕获 2 发生捕获事件 */
{
if(TIM2CH2_CAPTURE_STA & 0X40) /* 捕获到一个下降沿 */
{
TIM2CH2_CAPTURE_STA |= 0X80; /* 标记成功捕获到一次高电平脉宽 */
TIM2CH2_CAPTURE_VAL = TIM2->CCR2; /* 获取当前的捕获值. */
high = TIM2CH2_CAPTURE_STA & 0X3F;
high *= 65536; /* 溢出时间总和 */
high += TIM2CH2_CAPTURE_VAL; /* 得到总的高电平时间 */
high = high * 170 / 1000000;
printf("High:%lf m\r\n",high); /* 打印总的高点平时间 */
TIM2CH2_CAPTURE_STA = 0; /* 开启下一次捕获 */
TIM2->CCER &= ~(1 << 5); /* CC2P=0 设置为上升沿捕获 */
} else { /* 还未开始,第一次捕获上升沿 */
TIM2CH2_CAPTURE_STA = 0; /* 清空 */
TIM2CH2_CAPTURE_VAL = 0;
TIM2CH2_CAPTURE_STA |= 0X40; /* 标记捕获到了上升沿 */
TIM2->CNT = 0; /* 计数器清空 */
TIM2->CCER |= 1 << 5; /* CC2P=1 设置为下降沿捕获 */
}
}
}
TIM2->SR &= ~(1 << 0); /* 清除中断标志位 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 初始化定时器2
*
* 描述: 此函数初始化STM32定时器2,因为System_Clock_Init()函数将APB1的分频系数设置为2,
* 所以TIM2的时钟频率为APB1的2倍,而APB1为36M
* Tout = ((arr+1) * (psc+1))/ Tclk
* 参数: arr 自动重装值。
* psc 时钟预分频数
* 返回值:无
*********************************************************************************************************
*/
void Timer2_Init(u16 arr,u16 psc)
{
RCC->APB1ENR |= 1 << 0; /* TIM2时钟使能 */
/*
** 自动重装载值,计数器计数到这个值就会触发溢出中断
*/
TIM2->ARR = arr;
/*
** 预分频器,得到计数时钟,
** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s
*/
TIM2->

SC = psc;
/* 这两个东东要同时设置才可以使用中断 */
TIM2->DIER |= 1 << 0; /* 允许更新中断 */
TIM2->DIER |= 1 << 6; /* 允许触发中断 */
TIM2->CR1 |= 0x01; /* 使能定时器2 */
MY_NVIC_Init(1,2,TIM2_IRQChannel,2); /* 抢占1,子优先级2,组2 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 定时器3中断服务程序
*
* 描述: 此函数提供定时器3的中断服务程序
* 参数: 无
* 返回值:无
*********************************************************************************************************
*/
void TIM3_IRQHandler(void)
{
if(TIM3->SR & 0X0001) /* 溢出中断 */
{
/* 中断处理程序 */
LED_GRE = !LED_GRE;
}
TIM3->SR &= ~(1 << 0); /* 清除中断标志位 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 初始化定时器3
*
* 描述: 此函数初始化STM32定时器3,因为System_Clock_Init()函数将APB1的分频系数设置为2,
* 所以TIM3的时钟频率为APB1的2倍,而APB1为36M
* Tout = ((arr+1) * (psc+1))/ Tclk
* 参数: arr 自动重装值。
* psc 时钟预分频数
* 返回值:无
*********************************************************************************************************
*/
void Timer3_Init(u16 arr,u16 psc)
{
RCC->APB1ENR |= 1 << 1; /* TIM3时钟使能 */
/*
** 自动重装载值,计数器计数到这个值就会触发溢出中断
*/
TIM3->ARR = arr;
/*
** 预分频器,得到计数时钟,
** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s
*/
TIM3->

SC = psc;
/* 这两个东东要同时设置才可以使用中断 */
TIM3->DIER |= 1 << 0; /* 允许更新中断 */
TIM3->DIER |= 1 << 6; /* 允许触发中断 */
TIM3->CR1 |= 0x01; /* 使能定时器3 */
MY_NVIC_Init(1,3,TIM3_IRQChannel,2); /* 抢占1,子优先级3,组2 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 定时器4中断服务程序
*
* 描述: 此函数提供定时器3的中断服务程序
* 参数: 无
* 返回值:无
*********************************************************************************************************
*/
void TIM4_IRQHandler(void)
{
if(TIM4->SR & 0X0001) /* 溢出中断 */
{
/* 中断处理程序 */
LED_GRE = !LED_GRE;
}
TIM4->SR &= ~(1 << 0); /* 清除中断标志位 */
}
/*$PAGE*/
/*
*********************************************************************************************************
* 初始化定时器4
*
* 描述: 此函数初始化STM32定时器3,因为System_Clock_Init()函数将APB1的分频系数设置为2,
* 所以TIM4的时钟频率为APB1的2倍,而APB1为36M
* Tout = ((arr+1) * (psc+1))/ Tclk
* 参数: arr 自动重装值。
* psc 时钟预分频数
* 返回值:无
*********************************************************************************************************
*/
void Timer4_Init(u16 arr,u16 psc)
{
RCC->APB1ENR |= 1 << 2; /* TIM4时钟使能 */
/*
** 自动重装载值,计数器计数到这个值就会触发溢出中断
*/
TIM4->ARR = arr;
/*
** 预分频器,得到计数时钟,
** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s
*/
TIM4->

SC = psc;
/* 这两个东东要同时设置才可以使用中断 */
TIM4->DIER |= 1 << 0; /* 允许更新中断 */
TIM4->DIER |= 1 << 6; /* 允许触发中断 */
TIM4->CR1 |= 0x01; /* 使能定时器4 */
MY_NVIC_Init(1,1,TIM4_IRQChannel,2); /* 抢占1,子优先级3,组2 */
}
[/mw_shl_code]
这是超声波初始化函数
[mw_shl_code=c,true]/*
*********************************************************************************************************
* Embedded Systems Building Blocks
* Complete and Ready-to-Use Modules in C
*
* ULTRASOUND Module Driver
*
* (c) Copyright 2014, Fisher
*
* Filename : ultrasound.c
* Programmer : Fisher
*********************************************************************************************************
* DESCRIPTION
*
* 这个模块
* 提供的接口:
* 消耗的IO口:
*********************************************************************************************************
*/
/*$PAGE*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#include "ultrasound.h"
#include "timer.h"
// float high = 0.0;
/*$PAGE*/
/*
*********************************************************************************************************
* 超声波初始化
*
* 描述: 此函数初始化超声波相关的IO口
* 参数: 无
* 返回值:无
*********************************************************************************************************
*/
void ultrasound_init(void) {
TIM2_Cap_Init(0XFFFF,71); /* 1MHz频率计数 */
Timer1_Init(4999,7199);
RCC->APB2ENR |= 1 << 2; /* 使能PORTA时钟 */
GPIOA->CRL &= 0XFFFFFFF0; /* PA0 清除之前设置 */
GPIOA->CRL |= 0X00000003; /* PA0 输出 */
GPIOA->ODR |= 0 << 0; /* PA0 下拉 */
}[/mw_shl_code]
[mw_shl_code=c,true]
[/mw_shl_code]
[mw_shl_code=c,true]这是main函数[/mw_shl_code]
[mw_shl_code=c,true]#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "timer.h"
#include "led.h"
#include "ultrasound.h"
int main()
{
Stm32_Clock_Init(9); /* 系统时钟设置 */
delay_init(72); /* 延时初始化 */
usart1_init(72, 9600);
ultrasound_init();
LED_Init();
while(1)
{
LED_RED = !LED_RED;
delay_ms(20);
}
}
下面附上整个工程[/mw_shl_code]
[mw_shl_code=c,true]
[/mw_shl_code]