前言
本文是作者从2024年7月10日开始学习STM32准备2024年7月21日物联网设计大赛的备赛过程记录,希望本人的学习与准备过程能够为后来者提供一些帮助。
设备:STM32 F103 指南者
本节前言
本节为指南者系列入门篇笔记,学习视频为野火F103霸道/指南者视频教程_入门篇。
寄存器编程
GPIO
GPIO为STM32的通用输入输出端口(General-purpose input/output),STM32的GPIO被分为了很多组,每组各有16个引脚。STM32F103有GPIOA-GPIOG共7组,通过GPIO可以向外界输出高低电平,或者从外界读入高低电平。
GPIO有多种工作方式:输入模式(模拟/浮空/上拉/下拉)、输出模式(推挽/开漏)、复用模式(推挽/开漏),GPIO的模式设定由其CRL或CRH控制。
我们重点关注输入/输出模式。在输入模式下,引脚的输出功能被禁止,此时可以通过端口对应的输入数据寄存器GPIOx_IDR获取外界的高低电平状况;在输出模式下,输出数据寄存器GPIOx_ODR将控制对应引脚的高低电平。假如现在我们希望GPIOB的PB0口为输出模式,则需要在GPIOB_CRL中的CNF0和MODE0均设置为0,使得与其对应的PB0口为输出模式。
// 清空控制PB0的端口位
GPIOB_CRL &= ~( 0x0F<< (4*0));
// 配置PB0为通用推挽输出,速度为10M
GPIOB_CRL |= (1<<4*0);
IDR/ODR
IDR与ODR的高16位被保留无法使用,此时剩下的低16位和GPIO中的16个引脚一一对应,在输出模式下,若要控制Px0引脚输出低电平,只需要ODR中的第0位设置为0即可。
// PB0 输出 低电平
GPIOB_ODR &= ~(1<<0);
外设时钟
STM32相比于C51功耗更低的原因在于STM32的每个外设(包括GPIO组)都对应着一个时钟,且时钟默认关闭,因此如果我们想要某个外设能够正常工作,打开其外设时钟是必不可少的。而GPIO的时钟开关由外设时钟使能寄存器RCC_APB2ENR控制。
假如我们要开启GPIOB的外设时钟信号,只需要将RCC_APB2ENR中控制GPIOB的位设置为高电平即可。
// 开启GPIOB 端口时钟
RCC_APB2ENR |= (1<<3);
设置延时函数
作者在自己编写延时函数时,发现延时函数无法起作用
void Delay(int i){
for(;i>=0;i--);
}
通过查询资料发现,可能由于编译器的优化,将传入Delay函数的值都改为0了,使得延时函数无法起作用,可以通过修改int位volatile避免编译器优化。
void Delay(volatile i){
for(;i>=0;i--);
}
固件库编程
基础硬件库
H文件(stm32f10x_conf.h)
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F10x_CONF_H
#define __STM32F10x_CONF_H
/* Includes ------------------------------------------------------------------*/
/* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */
//#include "stm32f10x_adc.h"
//#include "stm32f10x_bkp.h"
//#include "stm32f10x_can.h"
//#include "stm32f10x_cec.h"
//#include "stm32f10x_crc.h"
//#include "stm32f10x_dac.h"
//#include "stm32f10x_dbgmcu.h"
//#include "stm32f10x_dma.h"
//#include "stm32f10x_exti.h"
//#include "stm32f10x_flash.h"
//#include "stm32f10x_fsmc.h"
#include "stm32f10x_gpio.h"
//#include "stm32f10x_i2c.h"
//#include "stm32f10x_iwdg.h"
//#include "stm32f10x_pwr.h"
#include "stm32f10x_rcc.h"
//#include "stm32f10x_rtc.h"
//#include "stm32f10x_sdio.h"
//#include "stm32f10x_spi.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_usart.h"
//#include "stm32f10x_wwdg.h"
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Uncomment the line below to expanse the "assert_param" macro in the
Standard Peripheral Library drivers code */
/* #define USE_FULL_ASSERT 1 */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function which reports
* the name of the source file and the source line number of the call
* that failed. If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
#endif /* __STM32F10x_CONF_H */
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
H文件(stm32f10x_it.h)
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F10x_IT_H
#define __STM32F10x_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
//声明全局变量作用范围
extern int read_dht11_finish;
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
#ifdef __cplusplus
}
#endif
#endif /* __STM32F10x_IT_H */
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
H文件(core_delay.h)
#ifndef __CORE_DELAY_H
#define __CORE_DELAY_H
#include "stm32f10x.h"
#define USE_DWT_DELAY 1 /* 使用dwt内核精确延时 */
#if USE_DWT_DELAY
#define USE_TICK_DELAY 0 /* 不使用SysTick延时 */
#else
#define USE_TICK_DELAY 1 /* 使用SysTick延时 */
#endif
/*简单任务管理*/
#define TASK_ENABLE 0
#define NumOfTask 3
#if USE_DWT_DELAY
#define Delay_ms(ms) CPU_TS_Tmr_Delay_MS(ms)
#define Delay_us(us) CPU_TS_Tmr_Delay_US(us)
/* 最大延时 60s=2的32次方/72000000 */
#define Delay_s(s) CPU_TS_Tmr_Delay_S(s)
/* 获取内核时钟频率 */
#define GET_CPU_ClkFreq() (SystemCoreClock)
#define SysClockFreq (SystemCoreClock)
/* 为方便使用,在延时函数内部调用CPU_TS_TmrInit函数初始化时间戳寄存器,
这样每次调用函数都会初始化一遍。
把本宏值设置为0,然后在main函数刚运行时调用CPU_TS_TmrInit可避免每次都初始化 */
#define CPU_TS_INIT_IN_DELAY_FUNCTION 0
/*******************************************************************************
* 函数声明
******************************************************************************/
uint32_t CPU_TS_TmrRd(void);
void CPU_TS_TmrInit(void);
//使用以下函数前必须先调用CPU_TS_TmrInit函数使能计数器,或使能宏CPU_TS_INIT_IN_DELAY_FUNCTION
//最大延时值为60秒
void CPU_TS_Tmr_Delay_US(uint32_t us);
#define CPU_TS_Tmr_Delay_MS(ms) CPU_TS_Tmr_Delay_US(ms*1000)
#define CPU_TS_Tmr_Delay_S(s) CPU_TS_Tmr_Delay_MS(s*1000)
#endif
#endif /* __CORE_DELAY_H */
C文件(stm32f10x_it.c)
#include "bsp_SysTick.h"
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init( void )
{
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
if ( SysTick_Config(SystemCoreClock / 100) ) // ST3.5.0库版本
{
/* Capture error */
while (1);
}
// 关闭滴答定时器
//SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
// 使能滴答定时器 10ms中断一次
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
}
C文件(core_delay.c)
#include "./dwt_delay/core_delay.h"
/*
**********************************************************************
* 时间戳相关寄存器定义
**********************************************************************
*/
/*
在Cortex-M里面有一个外设叫DWT(Data Watchpoint and Trace),
该外设有一个32位的寄存器叫CYCCNT,它是一个向上的计数器,
记录的是内核时钟运行的个数,最长能记录的时间为:
60s=2的32次方/72000000
(假设内核频率为72M,内核跳一次的时间大概为1/72M=13.8ns)
当CYCCNT溢出之后,会清0重新开始向上计数。
使能CYCCNT计数的操作步骤:
1、先使能DWT外设,这个由另外内核调试寄存器DEMCR的位24控制,写1使能
2、使能CYCCNT寄存器之前,先清0
3、使能CYCCNT寄存器,这个由DWT_CTRL(代码上宏定义为DWT_CR)的位0控制,写1使能
*/
#if USE_DWT_DELAY
#define DWT_CR *(__IO uint32_t *)0xE0001000
#define DWT_CYCCNT *(__IO uint32_t *)0xE0001004
#define DEM_CR *(__IO uint32_t *)0xE000EDFC
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
/**
* @brief 初始化时间戳
* @param 无
* @retval 无
* @note 使用延时函数前,必须调用本函数
*/
void CPU_TS_TmrInit(void)
{
/* 使能DWT外设 */
DEM_CR |= (uint32_t)DEM_CR_TRCENA;
/* DWT CYCCNT寄存器计数清0 */
DWT_CYCCNT = (uint32_t)0u;
/* 使能Cortex-M DWT CYCCNT寄存器 */
DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;
}
/**
* @brief 读取当前时间戳
* @param 无
* @retval 当前时间戳,即DWT_CYCCNT寄存器的值
*/
uint32_t CPU_TS_TmrRd(void)
{
return ((uint32_t)DWT_CYCCNT);
}
///**
// * @brief 读取当前时间戳
// * @param 无
// * @retval 当前时间戳,即DWT_CYCCNT寄存器的值
// * 此处给HAL库替换HAL_GetTick函数,用于os
// */
//uint32_t HAL_GetTick(void)
//{
// return ((uint32_t)DWT_CYCCNT*1000/SysClockFreq);
//}
/**
* @brief 采用CPU的内部计数实现精确延时,32位计数器
* @param us : 延迟长度,单位1 us
* @retval 无
* @note 使用本函数前必须先调用CPU_TS_TmrInit函数使能计数器,
或使能宏CPU_TS_INIT_IN_DELAY_FUNCTION
最大延时值为8秒,即8*1000*1000
*/
void CPU_TS_Tmr_Delay_US(__IO uint32_t us)
{
uint32_t ticks;
uint32_t told,tnow,tcnt=0;
/* 在函数内部初始化时间戳寄存器, */
#if (CPU_TS_INIT_IN_DELAY_FUNCTION)
/* 初始化时间戳并清零 */
CPU_TS_TmrInit();
#endif
ticks = us * (GET_CPU_ClkFreq() / 1000000); /* 需要的节拍数 */
tcnt = 0;
told = (uint32_t)CPU_TS_TmrRd(); /* 刚进入时的计数器值 */
while(1)
{
tnow = (uint32_t)CPU_TS_TmrRd();
if(tnow != told)
{
/* 32位计数器是递增计数器 */
if(tnow > told)
{
tcnt += tnow - told;
}
/* 重新装载 */
else
{
tcnt += UINT32_MAX - told + tnow;
}
told = tnow;
/*时间超过/等于要延迟的时间,则退出 */
if(tcnt >= ticks)break;
}
}
}
#endif
/*********************************************END OF FILE**********************/
SysTick(时钟)
H文件(bsp_SysTick.h)
#ifndef __SYSTICK_H
#define __SYSTICK_H
#include "stm32f10x.h"
void SysTick_Init( void );
#endif /* __SYSTICK_H */
C文件(bsp_SysTick.c)
#include "bsp_SysTick.h"
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init( void )
{
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
if ( SysTick_Config(SystemCoreClock / 100) ) // ST3.5.0库版本
{
/* Capture error */
while (1);
}
// 关闭滴答定时器
//SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
// 使能滴答定时器 10ms中断一次
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
}
/*********************************************END OF FILE**********************/
常用函数
// 初始化
SysTick_Init();
USART(串口)
H文件(bsp_usart.h)
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
/**
* 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
* 2-修改GPIO的宏
*/
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
// 串口2-USART2
//#define DEBUG_USARTx USART2
//#define DEBUG_USART_CLK RCC_APB1Periph_USART2
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOA
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
//#define DEBUG_USART_RX_GPIO_PORT GPIOA
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
//#define DEBUG_USART_IRQ USART2_IRQn
//#define DEBUG_USART_IRQHandler USART2_IRQHandler
// 串口3-USART3
//#define DEBUG_USARTx USART3
//#define DEBUG_USART_CLK RCC_APB1Periph_USART3
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOB
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
//#define DEBUG_USART_RX_GPIO_PORT GPIOB
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
//#define DEBUG_USART_IRQ USART3_IRQn
//#define DEBUG_USART_IRQHandler USART3_IRQHandler
// 串口4-UART4
//#define DEBUG_USARTx UART4
//#define DEBUG_USART_CLK RCC_APB1Periph_UART4
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOC
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
//#define DEBUG_USART_RX_GPIO_PORT GPIOC
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
//#define DEBUG_USART_IRQ UART4_IRQn
//#define DEBUG_USART_IRQHandler UART4_IRQHandler
// 串口5-UART5
//#define DEBUG_USARTx UART5
//#define DEBUG_USART_CLK RCC_APB1Periph_UART5
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOC
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
//#define DEBUG_USART_RX_GPIO_PORT GPIOD
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
//#define DEBUG_USART_IRQ UART5_IRQn
//#define DEBUG_USART_IRQHandler UART5_IRQHandler
void USART_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);
#endif /* __USART_H */
C文件(bso_usart.c)
#include "bsp_usart.h"
/**
* @brief 配置嵌套向量中断控制器NVIC
* @param 无
* @retval 无
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief USART GPIO 配置,工作参数配置
* @param 无
* @retval 无
*/
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
// 将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
// 配置 针数据字长
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(DEBUG_USARTx, &USART_InitStructure);
// 串口中断优先级配置
NVIC_Configuration();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
USART_ITConfig ( DEBUG_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断
// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
/***************** 发送一个字节 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/****************** 发送8位的数组 ************************/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
uint8_t i;
for(i=0; i<num; i++)
{
/* 发送一个字节数据到USART */
Usart_SendByte(pUSARTx,array[i]);
}
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
/***************** 发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}
/***************** 发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch&0XFF00)>>8;
/* 取出低八位 */
temp_l = ch&0XFF;
/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
常用函数
// 初始化
USART_Config();
// 使用串口输出信息
printf("txt");
// 从串口获取信息
ch = getchar();
LED
H文件(bsp_led.h)
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
/* 定义LED连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的LED引脚 */
// R-红色
#define LED1_GPIO_PORT GPIOB /* GPIO端口 */
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define LED1_GPIO_PIN GPIO_Pin_5 /* 连接到SCL时钟线的GPIO */
// G-绿色
#define LED2_GPIO_PORT GPIOB /* GPIO端口 */
#define LED2_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define LED2_GPIO_PIN GPIO_Pin_0 /* 连接到SCL时钟线的GPIO */
// B-蓝色
#define LED3_GPIO_PORT GPIOB /* GPIO端口 */
#define LED3_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define LED3_GPIO_PIN GPIO_Pin_1 /* 连接到SCL时钟线的GPIO */
/** the macro definition to trigger the led on or off
* 1 - off
*0 - on
*/
#define ON 0
#define OFF 1
/* 使用标准的固件库控制IO*/
#define LED1(a) if (a) \
GPIO_SetBits(LED1_GPIO_PORT,LED1_GPIO_PIN);\
else \
GPIO_ResetBits(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED2(a) if (a) \
GPIO_SetBits(LED2_GPIO_PORT,LED2_GPIO_PIN);\
else \
GPIO_ResetBits(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED3(a) if (a) \
GPIO_SetBits(LED3_GPIO_PORT,LED3_GPIO_PIN);\
else \
GPIO_ResetBits(LED3_GPIO_PORT,LED3_GPIO_PIN)
/* 直接操作寄存器的方法控制IO */
#define digitalHi(p,i) {p->BSRR=i;} //输出为高电平
#define digitalLo(p,i) {p->BRR=i;} //输出低电平
#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态
/* 定义控制IO的宏 */
#define LED1_TOGGLE digitalToggle(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_OFF digitalHi(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_ON digitalLo(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED2_TOGGLE digitalToggle(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED2_OFF digitalHi(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED2_ON digitalLo(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED3_TOGGLE digitalToggle(LED3_GPIO_PORT,LED3_GPIO_PIN)
#define LED3_OFF digitalHi(LED3_GPIO_PORT,LED3_GPIO_PIN)
#define LED3_ON digitalLo(LED3_GPIO_PORT,LED3_GPIO_PIN)
/* 基本混色,后面高级用法使用PWM可混出全彩颜色,且效果更好 */
//红
#define LED_RED \
LED1_ON;\
LED2_OFF\
LED3_OFF
//绿
#define LED_GREEN \
LED1_OFF;\
LED2_ON\
LED3_OFF
//蓝
#define LED_BLUE \
LED1_OFF;\
LED2_OFF\
LED3_ON
//黄(红+绿)
#define LED_YELLOW \
LED1_ON;\
LED2_ON\
LED3_OFF
//紫(红+蓝)
#define LED_PURPLE \
LED1_ON;\
LED2_OFF\
LED3_ON
//青(绿+蓝)
#define LED_CYAN \
LED1_OFF;\
LED2_ON\
LED3_ON
//白(红+绿+蓝)
#define LED_WHITE \
LED1_ON;\
LED2_ON\
LED3_ON
//黑(全部关闭)
#define LED_RGBOFF \
LED1_OFF;\
LED2_OFF\
LED3_OFF
void LED_GPIO_Config(void);
#endif /* __LED_H */
C文件(bsp_led.c)
#include "./led/bsp_led.h"
void LED_GPIO_Config(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启LED相关的GPIO外设时钟*/
RCC_APB2PeriphClockCmd( LED1_GPIO_CLK | LED2_GPIO_CLK | LED3_GPIO_CLK, ENABLE);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化GPIO*/
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;
/*调用库函数,初始化GPIO*/
GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = LED3_GPIO_PIN;
/*调用库函数,初始化GPIOF*/
GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);
/* 关闭所有led灯 */
GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
/* 关闭所有led灯 */
GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);
/* 关闭所有led灯 */
GPIO_SetBits(LED3_GPIO_PORT, LED3_GPIO_PIN);
}
void assert_failed(uint8_t* file, uint32_t line)
{
// 断言错误时执行的代码
LED1_ON;
}
/*********************************************END OF FILE**********************/
常用函数
// 初始化
LED_GPIO_Config();
// LEDx亮与灭
LED1_ON;
LED1_OFF;
// LED亮起部分颜色
LED_RED;
LED_BLUE;
LED_GREEN;
LED_YELLOW;
LED_WHITE;
// LED反转
LED1_TOGGLE;
LED2_TOGGLE;
LED3_TOGGLE;
KEY
H文件(bsp_key.h)
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
// 引脚定义
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA
#define KEY1_GPIO_PORT GPIOA
#define KEY1_GPIO_PIN GPIO_Pin_0
#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC
#define KEY2_GPIO_PORT GPIOC
#define KEY2_GPIO_PIN GPIO_Pin_13
/** 按键按下标置宏
* 按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0
* 若按键按下为低电平,把宏设置成KEY_ON=0 ,KEY_OFF=1 即可
*/
#define KEY_ON 1
#define KEY_OFF 0
void Key_GPIO_Config(void);
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
#endif /* __KEY_H */
C文件(bsp_key.c)
#include "./key/bsp_key.h"
/**
* @brief 配置按键用到的I/O口
* @param 无
* @retval 无
*/
void Key_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*开启按键端口的时钟*/
RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);
//选择按键的引脚
GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
// 设置按键的引脚为浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//使用结构体初始化按键
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);
//选择按键的引脚
GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;
//设置按键的引脚为浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//使用结构体初始化按键
GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 函数名:Key_Scan
* 描述 :检测是否有按键按下
* 输入 :GPIOx:x 可以是 A,B,C,D或者 E
* GPIO_Pin:待读取的端口位
* 输出 :KEY_OFF(没按下按键)、KEY_ON(按下按键)
*/
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
/*检测是否有按键按下 */
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
{
/*等待按键释放 */
while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
return KEY_ON;
}
else
return KEY_OFF;
}
/*********************************************END OF FILE**********************/
常用函数
// 初始化
Key_GPIO_Config();
// 检测按钮是否被按下
Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN);
DHT11(温湿度传感器)
H文件(bsp_dht11.h)
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"
/************************** DHT11 数据类型定义********************************/
typedef struct
{
uint8_t humi_int; //湿度的整数部分
uint8_t humi_deci; //湿度的小数部分
uint8_t temp_int; //温度的整数部分
uint8_t temp_deci; //温度的小数部分
uint8_t check_sum; //校验和
} DHT11_Data_TypeDef;
#define macDHT11_Dout_SCK_APBxClock_FUN RCC_APB2PeriphClockCmd
#define macDHT11_Dout_GPIO_CLK RCC_APB2Periph_GPIOE
#define macDHT11_Dout_GPIO_PORT GPIOE
#define macDHT11_Dout_GPIO_PIN GPIO_Pin_6
/************************** DHT11 函数宏定义********************************/
#define macDHT11_Dout_0 GPIO_ResetBits ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN )
#define macDHT11_Dout_1 GPIO_SetBits ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN )
#define macDHT11_Dout_IN() GPIO_ReadInputDataBit ( macDHT11_Dout_GPIO_PORT, macDHT11_Dout_GPIO_PIN )
/************************** DHT11 函数声明 ********************************/
void DHT11_Init ( void );
uint8_t DHT11_Read_TempAndHumidity ( DHT11_Data_TypeDef * DHT11_Data );
;
#endif /* __DHT11_H */
C文件(bsp_dht11.c)
#include "bsp_dht11.h"
#include "./dwt_delay/core_delay.h"
static void DHT11_GPIO_Config ( void );
static void DHT11_Mode_IPU ( void );
static void DHT11_Mode_Out_PP ( void );
static uint8_t DHT11_ReadByte ( void );
/**
* @brief DHT11 初始化函数
* @param 无
* @retval 无
*/
void DHT11_Init ( void )
{
DHT11_GPIO_Config ();
macDHT11_Dout_1; // 拉高GPIOB10
}
/*
* 函数名:DHT11_GPIO_Config
* 描述 :配置DHT11用到的I/O口
* 输入 :无
* 输出 :无
*/
static void DHT11_GPIO_Config ( void )
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启macDHT11_Dout_GPIO_PORT的外设时钟*/
macDHT11_Dout_SCK_APBxClock_FUN ( macDHT11_Dout_GPIO_CLK, ENABLE );
/*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
GPIO_Init ( macDHT11_Dout_GPIO_PORT, &GPIO_InitStructure );
}
/*
* 函数名:DHT11_Mode_IPU
* 描述 :使DHT11-DATA引脚变为上拉输入模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;
/*设置引脚模式为浮空输入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
/*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
GPIO_Init(macDHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 函数名:DHT11_Mode_Out_PP
* 描述 :使DHT11-DATA引脚变为推挽输出模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的macDHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = macDHT11_Dout_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化macDHT11_Dout_GPIO_PORT*/
GPIO_Init(macDHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 从DHT11读取一个字节,MSB先行
*/
static uint8_t DHT11_ReadByte ( void )
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
/*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/
while(macDHT11_Dout_IN()==Bit_RESET);
/*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
*通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时
*/
Delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可
if(macDHT11_Dout_IN()==Bit_SET)/* x us后仍为高电平表示数据“1” */
{
/* 等待数据1的高电平结束 */
while(macDHT11_Dout_IN()==Bit_SET);
temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行
}
else // x us后为低电平表示数据“0”
{
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
}
}
return temp;
}
/*
* 一次完整的数据传输为40bit,高位先出
* 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
*/
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
/*输出模式*/
DHT11_Mode_Out_PP();
/*主机拉低*/
macDHT11_Dout_0;
/*延时18ms*/
Delay_ms(18);
/*总线拉高 主机延时30us*/
macDHT11_Dout_1;
Delay_us(30); //延时30us
/*主机设为输入 判断从机响应信号*/
DHT11_Mode_IPU();
/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/
if(macDHT11_Dout_IN()==Bit_RESET)
{
/*轮询直到从机发出 的80us 低电平 响应信号结束*/
while(macDHT11_Dout_IN()==Bit_RESET);
/*轮询直到从机发出的 80us 高电平 标置信号结束*/
while(macDHT11_Dout_IN()==Bit_SET);
/*开始接收数据*/
DHT11_Data->humi_int= DHT11_ReadByte();
DHT11_Data->humi_deci= DHT11_ReadByte();
DHT11_Data->temp_int= DHT11_ReadByte();
DHT11_Data->temp_deci= DHT11_ReadByte();
DHT11_Data->check_sum= DHT11_ReadByte();
/*读取结束,引脚改为输出模式*/
DHT11_Mode_Out_PP();
/*主机拉高*/
macDHT11_Dout_1;
/*检查读取的数据是否正确*/
if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
return SUCCESS;
else
return ERROR;
}
else
return ERROR;
}
/*************************************END OF FILE******************************/
常用函数
// 初始化
DHT11_Init ();
// 读取温湿度信息
if( DHT11_Read_TempAndHumidity ( & DHT11_Data ) == SUCCESS){
printf("\nRead DHT11 Successfully!\nHumidity:%d.%d %RH \nTemperature: %d.%d℃ \r\n",
DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
}
ESP8266(WIFI模块)
H文件(bsp_esp8266.h)
#ifndef __BSP_ESP8266_H
#define __BSP_ESP8266_H
#include "stm32f10x.h"
#include "common.h"
#include <stdio.h>
#include <stdbool.h>
#if defined ( __CC_ARM )
#pragma anon_unions
#endif
/******************************* ESP8266 数据类型定义 ***************************/
typedef enum{
STA,
AP,
STA_AP
} ENUM_Net_ModeTypeDef;
typedef enum{
enumTCP,
enumUDP,
} ENUM_NetPro_TypeDef;
typedef enum{
Multiple_ID_0 = 0,
Multiple_ID_1 = 1,
Multiple_ID_2 = 2,
Multiple_ID_3 = 3,
Multiple_ID_4 = 4,
Single_ID_0 = 5,
} ENUM_ID_NO_TypeDef;
typedef enum{
OPEN = 0,
WEP = 1,
WPA_PSK = 2,
WPA2_PSK = 3,
WPA_WPA2_PSK = 4,
} ENUM_AP_PsdMode_TypeDef;
/******************************* ESP8266 外部全局变量声明 ***************************/
#define RX_BUF_MAX_LEN 1024 //最大接收缓存字节数
extern struct STRUCT_USARTx_Fram //串口数据帧的处理结构体
{
char Data_RX_BUF [ RX_BUF_MAX_LEN ];
union {
__IO u16 InfAll;
struct {
__IO u16 FramLength :15; // 14:0
__IO u16 FramFinishFlag :1; // 15
} InfBit;
};
} strEsp8266_Fram_Record;
extern struct STRUCT_USARTx_Fram strUSART_Fram_Record;
/******************************** ESP8266 连接引脚定义 ***********************************/
#define macESP8266_CH_PD_APBxClock_FUN RCC_APB2PeriphClockCmd
#define macESP8266_CH_PD_CLK RCC_APB2Periph_GPIOB
#define macESP8266_CH_PD_PORT GPIOB
#define macESP8266_CH_PD_PIN GPIO_Pin_8
#define macESP8266_RST_APBxClock_FUN RCC_APB2PeriphClockCmd
#define macESP8266_RST_CLK RCC_APB2Periph_GPIOB
#define macESP8266_RST_PORT GPIOB
#define macESP8266_RST_PIN GPIO_Pin_9
#define macESP8266_USART_BAUD_RATE 115200
#define macESP8266_USARTx USART3
#define macESP8266_USART_APBxClock_FUN RCC_APB1PeriphClockCmd
#define macESP8266_USART_CLK RCC_APB1Periph_USART3
#define macESP8266_USART_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define macESP8266_USART_GPIO_CLK RCC_APB2Periph_GPIOB
#define macESP8266_USART_TX_PORT GPIOB
#define macESP8266_USART_TX_PIN GPIO_Pin_10
#define macESP8266_USART_RX_PORT GPIOB
#define macESP8266_USART_RX_PIN GPIO_Pin_11
#define macESP8266_USART_IRQ USART3_IRQn
#define macESP8266_USART_INT_FUN USART3_IRQHandler
/*********************************************** ESP8266 函数宏定义 *******************************************/
#define macESP8266_Usart( fmt, ... ) USART_printf ( macESP8266_USARTx, fmt, ##__VA_ARGS__ )
#define macPC_Usart( fmt, ... ) printf ( fmt, ##__VA_ARGS__ )
//#define macPC_Usart( fmt, ... )
#define macESP8266_CH_ENABLE() GPIO_SetBits ( macESP8266_CH_PD_PORT, macESP8266_CH_PD_PIN )
#define macESP8266_CH_DISABLE() GPIO_ResetBits ( macESP8266_CH_PD_PORT, macESP8266_CH_PD_PIN )
#define macESP8266_RST_HIGH_LEVEL() GPIO_SetBits ( macESP8266_RST_PORT, macESP8266_RST_PIN )
#define macESP8266_RST_LOW_LEVEL() GPIO_ResetBits ( macESP8266_RST_PORT, macESP8266_RST_PIN )
/****************************************** ESP8266 函数声明 ***********************************************/
void ESP8266_Init ( void );
void ESP8266_Rst ( void );
bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime );
bool ESP8266_AT_Test ( void );
bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode );
bool ESP8266_JoinAP ( char * pSSID, char * pPassWord );
bool ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode );
bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx );
bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id);
bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver );
uint8_t ESP8266_Get_LinkStatus ( void );
uint8_t ESP8266_Get_IdLinkStatus ( void );
uint8_t ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength );
bool ESP8266_UnvarnishSend ( void );
void ESP8266_ExitUnvarnishSend ( void );
bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId );
char * ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx );
bool ESP8266_DHCP_CUR ( void );
#endif
H文件(bsp_esp8266_test.h)
#ifndef __ESP8266_TEST_H
#define __ESP8266_TEST_H
#include "stm32f10x.h"
/********************************** 用户需要设置的参数**********************************/
#define macUser_ESP8266_ApSsid "NUDTer" //要连接的热点的名称
#define macUser_ESP8266_ApPwd "12345678" //要连接的热点的密钥
#define macUser_ESP8266_TcpServer_IP "192.168.0.102" //要连接的服务器的 IP
#define macUser_ESP8266_TcpServer_Port "8000" //要连接的服务器的端口
/********************************** 外部全局变量 ***************************************/
extern volatile uint8_t ucTcpClosedFlag;
extern int read_dht11_finish;
/********************************** 测试函数声明 ***************************************/
void ESP8266_StaTcpClient_Unvarnish_ConfigTest(void);
void ESP8266_SendDHT11DataTest(void);
#endif
C文件(bsp_esp8266.c)
#include "bsp_esp8266.h"
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "./dwt_delay/core_delay.h"
static void ESP8266_GPIO_Config ( void );
static void ESP8266_USART_Config ( void );
static void ESP8266_USART_NVIC_Configuration ( void );
struct STRUCT_USARTx_Fram strEsp8266_Fram_Record = { 0 };
struct STRUCT_USARTx_Fram strUSART_Fram_Record = { 0 };
/**
* @brief ESP8266初始化函数
* @param 无
* @retval 无
*/
void ESP8266_Init ( void )
{
ESP8266_GPIO_Config ();
ESP8266_USART_Config ();
macESP8266_RST_HIGH_LEVEL();
macESP8266_CH_DISABLE();
}
/**
* @brief 初始化ESP8266用到的GPIO引脚
* @param 无
* @retval 无
*/
static void ESP8266_GPIO_Config ( void )
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/* 配置 CH_PD 引脚*/
macESP8266_CH_PD_APBxClock_FUN ( macESP8266_CH_PD_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = macESP8266_CH_PD_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init ( macESP8266_CH_PD_PORT, & GPIO_InitStructure );
/* 配置 RST 引脚*/
macESP8266_RST_APBxClock_FUN ( macESP8266_RST_CLK, ENABLE );
GPIO_InitStructure.GPIO_Pin = macESP8266_RST_PIN;
GPIO_Init ( macESP8266_RST_PORT, & GPIO_InitStructure );
}
/**
* @brief 初始化ESP8266用到的 USART
* @param 无
* @retval 无
*/
static void ESP8266_USART_Config ( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* config USART clock */
macESP8266_USART_APBxClock_FUN ( macESP8266_USART_CLK, ENABLE );
macESP8266_USART_GPIO_APBxClock_FUN ( macESP8266_USART_GPIO_CLK, ENABLE );
/* USART GPIO config */
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = macESP8266_USART_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(macESP8266_USART_TX_PORT, &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Pin = macESP8266_USART_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(macESP8266_USART_RX_PORT, &GPIO_InitStructure);
/* USART1 mode config */
USART_InitStructure.USART_BaudRate = macESP8266_USART_BAUD_RATE;
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(macESP8266_USARTx, &USART_InitStructure);
/* 中断配置 */
USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中断
USART_ITConfig ( macESP8266_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断
ESP8266_USART_NVIC_Configuration ();
USART_Cmd(macESP8266_USARTx, ENABLE);
}
/**
* @brief 配置 ESP8266 USART 的 NVIC 中断
* @param 无
* @retval 无
*/
static void ESP8266_USART_NVIC_Configuration ( void )
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig ( macNVIC_PriorityGroup_x );
/* Enable the USART2 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = macESP8266_USART_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*
* 函数名:ESP8266_Rst
* 描述 :重启WF-ESP8266模块
* 输入 :无
* 返回 : 无
* 调用 :被 ESP8266_AT_Test 调用
*/
void ESP8266_Rst ( void )
{
#if 0
ESP8266_Cmd ( "AT+RST", "OK", "ready", 2500 );
#else
macESP8266_RST_LOW_LEVEL();
Delay_ms ( 500 );
macESP8266_RST_HIGH_LEVEL();
#endif
}
/*
* 函数名:ESP8266_Cmd
* 描述 :对WF-ESP8266模块发送AT指令
* 输入 :cmd,待发送的指令
* reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系
* waittime,等待响应的时间
* 返回 : 1,指令发送成功
* 0,指令发送失败
* 调用 :被外部调用
*/
bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime )
{
strEsp8266_Fram_Record .InfBit .FramLength = 0; //从新开始接收新的数据包
macESP8266_Usart ( "%s\r\n", cmd );
if ( ( reply1 == 0 ) && ( reply2 == 0 ) ) //不需要接收数据
return true;
Delay_ms ( waittime ); //延时
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';
macPC_Usart ( "%s", strEsp8266_Fram_Record .Data_RX_BUF );
strEsp8266_Fram_Record .InfBit .FramLength = 0; //清除接收标志
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
if ( ( reply1 != 0 ) && ( reply2 != 0 ) )
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) ||
( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
else if ( reply1 != 0 )
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) );
else
return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
}
/*
* 函数名:ESP8266_AT_Test
* 描述 :对WF-ESP8266模块进行AT测试启动
* 输入 :无
* 返回 : 无
* 调用 :被外部调用
*/
//void ESP8266_AT_Test ( void )
//{
// macESP8266_RST_HIGH_LEVEL();
//
// Delay_ms ( 1000 );
//
// while ( ! ESP8266_Cmd ( "AT", "OK", NULL, 500 ) ) ESP8266_Rst ();
//}
bool ESP8266_AT_Test ( void )
{
char count=0;
macESP8266_RST_HIGH_LEVEL();
printf("\r\nAT测试.....\r\n");
Delay_ms ( 2000 );
while ( count < 10 )
{
printf("\r\nAT测试次数 %d......\r\n", count);
if( ESP8266_Cmd ( "AT", "OK", NULL, 500 ) )
{
printf("\r\nAT测试启动成功 %d......\r\n", count);
return 1;
}
ESP8266_Rst();
++ count;
}
return 0;
}
/*
* 函数名:ESP8266_Net_Mode_Choose
* 描述 :选择WF-ESP8266模块的工作模式
* 输入 :enumMode,工作模式
* 返回 : 1,选择成功
* 0,选择失败
* 调用 :被外部调用
*/
bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode )
{
switch ( enumMode )
{
case STA:
return ESP8266_Cmd ( "AT+CWMODE=1", "OK", "no change", 2500 );
case AP:
return ESP8266_Cmd ( "AT+CWMODE=2", "OK", "no change", 2500 );
case STA_AP:
return ESP8266_Cmd ( "AT+CWMODE=3", "OK", "no change", 2500 );
default:
return false;
}
}
bool ESP8266_DHCP_CUR ( )
{
char cCmd [40];
sprintf ( cCmd, "AT+CWDHCP_CUR=1,1");
return ESP8266_Cmd ( cCmd, "OK", NULL, 500 );
}
/*
* 函数名:ESP8266_JoinAP
* 描述 :WF-ESP8266模块连接外部WiFi
* 输入 :pSSID,WiFi名称字符串
* :pPassWord,WiFi密码字符串
* 返回 : 1,连接成功
* 0,连接失败
* 调用 :被外部调用
*/
bool ESP8266_JoinAP ( char * pSSID, char * pPassWord )
{
char cCmd [120];
sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord );
return ESP8266_Cmd ( cCmd, "OK", NULL, 5000 );
}
/*
* 函数名:ESP8266_BuildAP
* 描述 :WF-ESP8266模块创建WiFi热点
* 输入 :pSSID,WiFi名称字符串
* :pPassWord,WiFi密码字符串
* :enunPsdMode,WiFi加密方式代号字符串
* 返回 : 1,创建成功
* 0,创建失败
* 调用 :被外部调用
*/
bool ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode )
{
char cCmd [120];
sprintf ( cCmd, "AT+CWSAP=\"%s\",\"%s\",1,%d", pSSID, pPassWord, enunPsdMode );
return ESP8266_Cmd ( cCmd, "OK", 0, 1000 );
}
/*
* 函数名:ESP8266_Enable_MultipleId
* 描述 :WF-ESP8266模块启动多连接
* 输入 :enumEnUnvarnishTx,配置是否多连接
* 返回 : 1,配置成功
* 0,配置失败
* 调用 :被外部调用
*/
bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx )
{
char cStr [20];
sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );
return ESP8266_Cmd ( cStr, "OK", 0, 500 );
}
/*
* 函数名:ESP8266_Link_Server
* 描述 :WF-ESP8266模块连接外部服务器
* 输入 :enumE,网络协议
* :ip,服务器IP字符串
* :ComNum,服务器端口字符串
* :id,模块连接服务器的ID
* 返回 : 1,连接成功
* 0,连接失败
* 调用 :被外部调用
*/
bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id)
{
char cStr [100] = { 0 }, cCmd [120];
switch ( enumE )
{
case enumTCP:
sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", ip, ComNum );
break;
case enumUDP:
sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", ip, ComNum );
break;
default:
break;
}
if ( id < 5 )
sprintf ( cCmd, "AT+CIPSTART=%d,%s", id, cStr);
else
sprintf ( cCmd, "AT+CIPSTART=%s", cStr );
return ESP8266_Cmd ( cCmd, "OK", "ALREAY CONNECT", 4000 );
}
/*
* 函数名:ESP8266_StartOrShutServer
* 描述 :WF-ESP8266模块开启或关闭服务器模式
* 输入 :enumMode,开启/关闭
* :pPortNum,服务器端口号字符串
* :pTimeOver,服务器超时时间字符串,单位:秒
* 返回 : 1,操作成功
* 0,操作失败
* 调用 :被外部调用
*/
bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver )
{
char cCmd1 [120], cCmd2 [120];
if ( enumMode )
{
sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 1, pPortNum );
sprintf ( cCmd2, "AT+CIPSTO=%s", pTimeOver );
return ( ESP8266_Cmd ( cCmd1, "OK", 0, 500 ) &&
ESP8266_Cmd ( cCmd2, "OK", 0, 500 ) );
}
else
{
sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 0, pPortNum );
return ESP8266_Cmd ( cCmd1, "OK", 0, 500 );
}
}
/*
* 函数名:ESP8266_Get_LinkStatus
* 描述 :获取 WF-ESP8266 的连接状态,较适合单端口时使用
* 输入 :无
* 返回 : 2,获得ip
* 3,建立连接
* 3,失去连接
* 0,获取状态失败
* 调用 :被外部调用
*/
uint8_t ESP8266_Get_LinkStatus ( void )
{
if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) )
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:2\r\n" ) )
return 2;
else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:3\r\n" ) )
return 3;
else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:4\r\n" ) )
return 4;
}
return 0;
}
/*
* 函数名:ESP8266_Get_IdLinkStatus
* 描述 :获取 WF-ESP8266 的端口(Id)连接状态,较适合多端口时使用
* 输入 :无
* 返回 : 端口(Id)的连接状态,低5位为有效位,分别对应Id5~0,某位若置1表该Id建立了连接,若被清0表该Id未建立连接
* 调用 :被外部调用
*/
uint8_t ESP8266_Get_IdLinkStatus ( void )
{
uint8_t ucIdLinkStatus = 0x00;
if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) )
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:0," ) )
ucIdLinkStatus |= 0x01;
else
ucIdLinkStatus &= ~ 0x01;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:1," ) )
ucIdLinkStatus |= 0x02;
else
ucIdLinkStatus &= ~ 0x02;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:2," ) )
ucIdLinkStatus |= 0x04;
else
ucIdLinkStatus &= ~ 0x04;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:3," ) )
ucIdLinkStatus |= 0x08;
else
ucIdLinkStatus &= ~ 0x08;
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:4," ) )
ucIdLinkStatus |= 0x10;
else
ucIdLinkStatus &= ~ 0x10;
}
return ucIdLinkStatus;
}
/*
* 函数名:ESP8266_Inquire_ApIp
* 描述 :获取 F-ESP8266 的 AP IP
* 输入 :pApIp,存放 AP IP 的数组的首地址
* ucArrayLength,存放 AP IP 的数组的长度
* 返回 : 0,获取失败
* 1,获取成功
* 调用 :被外部调用
*/
uint8_t ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength )
{
char uc;
char * pCh;
ESP8266_Cmd ( "AT+CIFSR", "OK", 0, 500 );
pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "APIP,\"" );
if ( pCh )
pCh += 6;
else
return 0;
for ( uc = 0; uc < ucArrayLength; uc ++ )
{
pApIp [ uc ] = * ( pCh + uc);
if ( pApIp [ uc ] == '\"' )
{
pApIp [ uc ] = '\0';
break;
}
}
return 1;
}
/*
* 函数名:ESP8266_UnvarnishSend
* 描述 :配置WF-ESP8266模块进入透传发送
* 输入 :无
* 返回 : 1,配置成功
* 0,配置失败
* 调用 :被外部调用
*/
bool ESP8266_UnvarnishSend ( void )
{
if ( ! ESP8266_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 ) )
return false;
return
ESP8266_Cmd ( "AT+CIPSEND", "OK", ">", 500 );
}
/*
* 函数名:ESP8266_ExitUnvarnishSend
* 描述 :配置WF-ESP8266模块退出透传模式
* 输入 :无
* 返回 : 无
* 调用 :被外部调用
*/
void ESP8266_ExitUnvarnishSend ( void )
{
Delay_ms ( 1000 );
macESP8266_Usart ( "+++" );
Delay_ms ( 500 );
}
/*
* 函数名:ESP8266_SendString
* 描述 :WF-ESP8266模块发送字符串
* 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式
* :pStr,要发送的字符串
* :ulStrLength,要发送的字符串的字节数
* :ucId,哪个ID发送的字符串
* 返回 : 1,发送成功
* 0,发送失败
* 调用 :被外部调用
*/
bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId )
{
char cStr [20];
bool bRet = false;
if ( enumEnUnvarnishTx )
{
macESP8266_Usart ( "%s", pStr );
bRet = true;
}
else
{
if ( ucId < 5 )
sprintf ( cStr, "AT+CIPSEND=%d,%d", ucId, ulStrLength + 2 );
else
sprintf ( cStr, "AT+CIPSEND=%d", ulStrLength + 2 );
ESP8266_Cmd ( cStr, "> ", 0, 1000 );
bRet = ESP8266_Cmd ( pStr, "SEND OK", 0, 1000 );
}
return bRet;
}
/*
* 函数名:ESP8266_ReceiveString
* 描述 :WF-ESP8266模块接收字符串
* 输入 :enumEnUnvarnishTx,声明是否已使能了透传模式
* 返回 : 接收到的字符串首地址
* 调用 :被外部调用
*/
char * ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx )
{
char * pRecStr = 0;
strEsp8266_Fram_Record .InfBit .FramLength = 0;
strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;
while ( ! strEsp8266_Fram_Record .InfBit .FramFinishFlag );
strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';
if ( enumEnUnvarnishTx )
pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
else
{
if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD" ) )
pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
}
return pRecStr;
}
C文件(bsp_esp8266_test.c)
#include "bsp_esp8266_test.h"
#include "bsp_esp8266.h"
#include "./dwt_delay/core_delay.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "bsp_dht11.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#define LED_CMD_NUMBER 8
char *ledCmd[8] = { "LED_RED","LED_GREEN","LED_BLUE","LED_YELLOW","LED_PURPLE","LED_CYAN","LED_WHITE","LED_RGBOFF" };
DHT11_Data_TypeDef DHT11_Data;
volatile uint8_t ucTcpClosedFlag = 0;
/**
* @brief 获取网络调试助手和串口调试助手发来的信息
* @param 无
* @retval 无
*/
void Get_ESP82666_Cmd( char * cmd)
{
uint8_t i;
for(i = 0;i < LED_CMD_NUMBER; i++)
{
if(( bool ) strstr ( cmd, ledCmd[i] ))
break;
}
switch(i)
{
case 0:
LED_RED;
break;
case 1:
LED_GREEN;
break;
case 2:
LED_BLUE;
break;
case 3:
LED_YELLOW;
break;
case 4:
LED_PURPLE;
break;
case 5:
LED_CYAN;
break;
case 6:
LED_WHITE;
break;
case 7:
LED_RGBOFF;
break;
default:
break;
}
}
/**
* @brief ESP8266 StaTcpClient Unvarnish 配置测试函数
* @param 无
* @retval 无
*/
void ESP8266_StaTcpClient_Unvarnish_ConfigTest(void)
{
printf( "\r\n正在配置 ESP8266 ......\r\n" );
printf( "\r\n使能 ESP8266 ......\r\n" );
macESP8266_CH_ENABLE();
while( ! ESP8266_AT_Test() );
while( ! ESP8266_DHCP_CUR () );
printf( "\r\n正在配置工作模式 STA ......\r\n" );
while( ! ESP8266_Net_Mode_Choose ( STA ) );
printf( "\r\n正在连接 WiFi ......\r\n" );
while( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd ) );
printf( "\r\n禁止多连接 ......\r\n" );
while( ! ESP8266_Enable_MultipleId ( DISABLE ) );
printf( "\r\n正在连接 Server ......\r\n" );
while( ! ESP8266_Link_Server ( enumTCP, macUser_ESP8266_TcpServer_IP, macUser_ESP8266_TcpServer_Port, Single_ID_0 ) );
printf( "\r\n进入透传发送模式 ......\r\n" );
while( ! ESP8266_UnvarnishSend () );
printf( "\r\n配置 ESP8266 完毕\r\n" );
}
/**
* @brief ESP8266 发送DHT11数据测试函数
* @param 无
* @retval 无
*/
void ESP8266_SendDHT11DataTest(void)
{
char cStr [ 100 ] = { 0 };
uint8_t ucStatus;
if( 1 == read_dht11_finish )
sprintf ( cStr, "\r\n\r\n读取DHT11成功!\r\n湿度为%d.%d %RH ,温度为 %d.%d℃ \r\n",
DHT11_Data.humi_int, DHT11_Data.humi_deci, DHT11_Data.temp_int, DHT11_Data.temp_deci );
else
sprintf ( cStr, "Read DHT11 ERROR!\r\n" );
printf ( "%s", cStr ); //打印读取 DHT11 温湿度信息
ESP8266_SendString ( ENABLE, cStr, 0, Single_ID_0 ); //发送 DHT11 温湿度信息到网络调试助手
if ( ucTcpClosedFlag ) //检测是否失去连接
{
ESP8266_ExitUnvarnishSend (); //退出透传模式
do ucStatus = ESP8266_Get_LinkStatus (); //获取连接状态
while ( ! ucStatus );
if ( ucStatus == 4 ) //确认失去连接后重连
{
printf ( "\r\n正在重连热点和服务器 ......\r\n" );
while ( ! ESP8266_JoinAP ( macUser_ESP8266_ApSsid, macUser_ESP8266_ApPwd ) );
while ( ! ESP8266_Link_Server ( enumTCP, macUser_ESP8266_TcpServer_IP, macUser_ESP8266_TcpServer_Port, Single_ID_0 ) );
printf ( "\r\n重连热点和服务器成功\r\n" );
}
while ( ! ESP8266_UnvarnishSend () );
}
}
常用函数
// 初始化
ESP8266_Init ();
CPU_TS_TmrInit();
ESP8266_StaTcpClient_Unvarnish_ConfigTest();
// 发送温湿度信息
ESP8266_SendDHT11DataTest();
光敏电阻
接线方式
VCC接到SPI1的5V引脚,GND接到SPI1的GND引脚,D0接到SPI1的C13引脚
H文件(bsp_ldr.h)
#ifndef __LDR_H
#define __LDR_H
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
// 引脚定义
#define LDR_GPIO_CLK RCC_APB2Periph_GPIOC
#define LDR_GPIO_PORT GPIOC
#define LDR_GPIO_PIN GPIO_Pin_13
/** 按键按下标置宏
* 按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0
* 若按键按下为低电平,把宏设置成KEY_ON=0 ,KEY_OFF=1 即可
*/
#define LDR_ON 1 // 有光
#define LDR_OFF 0 // 无光
void LDR_GPIO_Config(void);
uint8_t LDR_Test(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
#endif /* __LDR_H */
C文件(bsp_ldr.c)
#include "./ldr/bsp_ldr.h"
#include "bsp_led.h"
/**
* @brief 配置光敏用到的I/O口
* @param 无
* @retval 无
*/
void LDR_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*开启端口的时钟*/
RCC_APB2PeriphClockCmd(LDR_GPIO_CLK,ENABLE);
//选择输入的引脚
GPIO_InitStructure.GPIO_Pin = LDR_GPIO_PIN;
// 设置光敏输入的引脚为下拉输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(LDR_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 函数名:光敏电阻测试
* 描述 :检测光敏电阻的状态
* 输入 :GPIOx:x 可以是 A,B,C,D或者 E
* GPIO_Pin:待读取的端口位
* 输出 :LDR_ON:有光 LDR_OFF:无光
*/
uint8_t LDR_Test(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
/*检测光敏输入状态 */
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == 1 )
{
return LDR_OFF; // 无光
}
else
return LDR_ON; // 有光
}
/*********************************************END OF FILE**********************/
常用函数
/* 光敏端口初始化 */
LDR_GPIO_Config();
// 轮询光敏状态,若有光则点亮灯
while(1)
{
if (LDR_Test(LDR_GPIO_PORT,LDR_GPIO_PIN) == LDR_ON)
LED2_ON; // 有光灯亮
else
LED2_OFF; // 无光灯灭
}