注意!!!!一定要 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
五、運行結果:

最后,小白的學習筆記,歡迎大佬指教,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297377.html
標籤:其他
上一篇:介紹2個有趣的IoT的專案
