项目四:串口打印超声波测距
Posted 鑫仔_要变强
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目四:串口打印超声波测距相关的知识,希望对你有一定的参考价值。
注意!!!!一定要 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
打开复用功能时钟,虽然没用复用功能。
一、串口通信基础知识
1、STM32的串口通信接口 。
UART:通用异步收发器 。
USART:通用同步异步收发器 。
大容量STM32F10x系列芯片,包含3个USART和2个UART。
2、通信引脚RXD与TXD连接方式
3、通信数据流动过程
4、需要配置的串口参数
5、与串口相关的的库函数
6、库函数初始化串口步骤
6、代码
void uart_init1(u32 bound)
{
//GPIO define
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //open USART1,GPIOA clk
USART_DeInit(USART1); //release uart1
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //output mode
GPIO_Init(GPIOA, &GPIO_InitStructure); // Set PA9
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING;//
GPIO_Init(GPIOA, &GPIO_InitStructure); //Set PA10
//Usart1 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=4 ;//
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //
NVIC_Init(&NVIC_InitStructure); //
//USART1
USART_InitStructure.USART_BaudRate = bound;//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(USART1, &USART_InitStructure); //
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//
USART_Cmd(USART1, ENABLE); //
}
二、超声波基础知识
前言:SR04是利用超声波特性检测距离的传感器。其带有两个超声波探头,分别用作发射和接收超声波。其测量的范围是3-500cm。
1、基本原理
(1)先使用STM32的数字引脚13向TRIG脚输入至少10us的高电平信号,触发模块的测距功能。
(2)测距功能触发后,模块将自动发出 8 个 40kHz 的超声波脉冲,并自动检测是否有信号返回,这一步由模块内部自动完成。
(3)一旦检测到有回波信号则ECHO引脚会输出高电平。高电平持续的时间就是超声波从发射到返回的时间。此时可以使用定时器获取高电平的时间, 并计算出距被测物体的实际距离。公式: 距离=高电平时间*声速(340M/S)/2。
2、电路图
3、库函数编写流程
(1)初始化超声波引脚,打开相应管脚时钟。
(2)由于需要运用定时器测量返回的高电平的时间,所以需要对定时器(周期为1ms)进行初始化。
(3)由公式: 距离=高电平时间*声速(340M/S)/2,所以还需要编写一个函数把测量的时间转换为距离,测量五次取平均值。
三、总体编程流程
1、串口初始化(有中断),打开串口。
2、超声波管脚初始化。
3、定时器初始化(有中断)。
4、测距函数编写
4、主函数输出
四、代码(注释详细)
main.c
#include "motor.h"
#include "stdio.h"
#include "delay.h"
#include "stm32f10x.h"
#include "followline.h"
#include "sys.h"
#include "ultrasonic.h"
u8 UART3_data,UART1_data;
u8 UART3_rcv[20],UART3_rcv_count;
u8 UART1_rcv[50],UART1_rcv_count,Uart1_finish;
int main(void)
{
float length;
delay_init();//延迟初始化
uart_init1(9600);//串口初始化
ultrasonic_gpio_init();//超声波管脚初始化
ultrasonic_time2_init();//超声波定时器初始化
while(1)
{
printf("start work!!\\n");
length=transfer_ditigal();
printf("distance:%fcm\\n",length);
delay_s(1);
}
}
ultrasonic.c
#include "ultrasonic.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
int overcount;//计数变量
/************************超声波管脚初始化***************************************/
void ultrasonic_gpio_init(void)
{
//超声波发送管脚
//定义GPIO_A初始化的结构体
GPIO_InitTypeDef GPIO_InitStruct_A;
//打开PA管脚的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//将管脚PB4特殊功能关掉
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
//配置PA15的参数
GPIO_InitStruct_A.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct_A.GPIO_Pin=GPIO_Pin_15;
GPIO_InitStruct_A.GPIO_Speed=GPIO_Speed_50MHz;
//初始化PA15管脚
GPIO_Init(GPIOA, &GPIO_InitStruct_A);
//置PA15低位
GPIO_ResetBits(GPIOA, GPIO_Pin_15);
//超声波接收管脚
//配置PA12的参数
GPIO_InitStruct_A.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStruct_A.GPIO_Pin=GPIO_Pin_12;
//初始化PA12管脚
GPIO_Init(GPIOA, &GPIO_InitStruct_A);
}
/************************************************************************************************************/
/********************************超声使用定时器2初始化*******************************************************/
void ultrasonic_time2_init(void)
{
//定义TIME_2初始化的结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct_TIME2;
//打开定时器2的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//配置TIME_2的参数
TIM_TimeBaseInitStruct_TIME2.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct_TIME2.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct_TIME2.TIM_Period=999;
TIM_TimeBaseInitStruct_TIME2.TIM_Prescaler=71;
//初始化TIME_2
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct_TIME2);
//定义NVIC初始化的结构体
NVIC_InitTypeDef NVIC_InitStruct;
//中断分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
//配置NVIC的参数
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
//中断NVIC的初始化
NVIC_Init(&NVIC_InitStruct);
//清除定时器TIME_2更新中断标志
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
//开启定时器TIME_2的中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
//使能定时器TIME_2
//TIM_Cmd(TIM2,ENABLE );
}
/*************************************************************************************************************************/
/*********************************************距离测量函数*********************************************************************/
float transfer_ditigal(void)
{
float length =0,sum=0;
u16 time;
unsigned int i=0;
/*测则5次数据计算—次平均值*/
while(i!=5)
{
GPIO_SetBits(GPIOA,GPIO_Pin_15);//拉高信号,作为触发信号
delay_us(20);//高电平信号超过10us
GPIO_ResetBits(GPIOA,GPIO_Pin_15);
/*等待回响信号*/
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12) ==RESET);
TIM_Cmd(TIM2,ENABLE);//回响信号到来,开启定时器计数
i+=1; //每收到一次回响信号+1收到5次就计算均值
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)== SET);//回响信号消失
TIM_Cmd(TIM2,DISABLE) ;//关闭定时器
time=TIM_GetCounter(TIM2);//获取计TIw2数寄存器中的计数值,一边计算回响信号时间
length=(time+overcount*1000)/58.0;//通过回响信号计算距离
sum=length+sum;
TIM2->CNT = 0; //将tiem2计数寄存器的计数值清零
overcount = 0;//中断溢出次数清零
delay_ms(1);
}
length =sum/5;
return length;//距离作为函数返回值
}
/**********************************************************************************************************************/
void TIM2_IRQHandler() //TIM2中断
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update))//检查TIM2更新中断发生与否
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除TIM2更新中断标志
overcount++;
}
}
ultrasonic.h
#ifndef __ULTRASONIC_H
#define __ULTRASONIC_H
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
#include "delay.h"
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
float transfer_ditigal(void);//距离展示
void ultrasonic_gpio_init(void);//超声波管脚初始化
void ultrasonic_time2_init(void);//超声波定时器初始化
#endif
usart.c
#include "sys.h"
#include "ultrasonic.h"
#include "stdio.h"
#include "sys.h"
#include "usart.h"
extern u8 UART3_data,UART1_data;
extern u8 UART3_rcv[20],UART3_rcv_count;
extern u8 UART1_rcv[50],UART1_rcv_count,Uart1_finish;
//uart1
//bound:9600
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit (int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0)
; //循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
void uart_init1(u32 bound)
{
//GPIO define
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //open USART1,GPIOA clk
USART_DeInit(USART1); //release uart1
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //output mode
GPIO_Init(GPIOA, &GPIO_InitStructure); // Set PA9
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING;//
GPIO_Init(GPIOA, &GPIO_InitStructure); //Set PA10
//Usart1 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=4 ;//
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //
NVIC_Init(&NVIC_InitStructure); //
//USART1
USART_InitStructure.USART_BaudRate = bound;//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(USART1, &USART_InitStructure); //
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//
USART_Cmd(USART1, ENABLE); //
}
//uart3
//bound:9600
void uart_init3(u32 bound){
//GPIO
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //open USART3 clk
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //open GPIOB clk
USART_DeInit(USART3); //release uart3
//USART3_TX PB.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB.10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //output mode
GPIO_Init(GPIOB, &GPIO_InitStructure); //configure PB10
//USART3_RX PB.11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//input mode
GPIO_Init(GPIOB, &GPIO_InitStructure); //configure PB11
//Usart3 NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=5 ;//
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //
NVIC_Init(&NVIC_InitStructure); //
//USART
USART_InitStructure.USART_BaudRate = bound;//9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//data bit
USART_InitStructure.USART_StopBits = USART_StopBits_1;//stop bit
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(USART3, &USART_InitStructure); //
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//
USART_Cmd(USART3, ENABLE); //
}
void USART1_SendByByter(u8 Data)
{
//
USART_GetFlagStatus(USART1, USART_FLAG_TC);
USART_SendData(USART1, Data);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
void USART3_SendByByter(u8 Data)
{
//
USART_GetFlagStatus(USART3, USART_FLAG_TC);
USART_SendData(USART3, Data);
while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
}
void USART1_IRQHandler(void) //uart1 ISR
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //
UART1_data=Res;
if(Res==0x7E && UART1_rcv_count==0)
{
UART1_rcv[UART1_rcv_count++]=Res;
}
else if(Res!=0x7E && UART1_rcv_count>0)
{
UART1_rcv[UART1_rcv_count++]=Res;
}
else if(Res==0x7E && UART1_rcv_count>0)
{
UART1_rcv[UART1_rcv_count++]=Res;
Uart1_finish=2;
}
else
;
}
}
void USART3_IRQHandler(void) //uart3 ISR
{
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //RX set
{
UART3_data=USART_ReceiveData(USART3);//(USART1->DR); //
UART3_rcv[UART3_rcv_count]=UART3_data;
if(UART3_rcv_count<6) UART3_rcv_count++;
}
}
sys.h
#ifndef __SYS_H
#define __SYS_H
#include "stm32f10x.h"
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32开发板
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/8/18
//版本:V1.7
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved
//
//0,不支持ucos
//1,支持ucos
#define SYSTEM_SUPPORT_OS 0 //定义系统文件夹是否支持UCOS
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
void USART1_SendByByter(u8 Data);
void uart_init1(u32 bound);
#endif
五、运行结果:
最后,小白的学习笔记,欢迎大佬指教。
以上是关于项目四:串口打印超声波测距的主要内容,如果未能解决你的问题,请参考以下文章
STM32F103x/Free RTOS系统学习笔记之SR04超声波测距串口输出-CXM