本篇文章主要供本人使用,使用的是标准库,如果能帮助你的尽管CV就好,持续更新!!!
正文开始
补充一个C语言语法
‘\’这个是续行符,后面不能跟任何东西(空格也不行)
一.GPIO构建库编程流程
1.初始化时钟:
调用RCC_APB2PeriphClockCmd 函数(在STM32f10x_rcc.h中)
2.创建初始化GPIO结构体
3.调用初始化函数
//GPIO_XXX.h文件
//在STM32F10x.h中能找到GPIOX(X=A,B,C...)
#define USART_GPIO_PORT_TX GPIOA
//在STM32F10x_gpio.h中能找到
#define USART_GPIO_PIN_TX GP0IO_Pin_9
//在rcc头文件中拉取GPIOA的时钟线
#define USART_GPIO_CLK RCC_APB2Periph_GPIOA
//GPIO_XXX.c文件
void GPIO_Config()
{
//首先我们创建GPIO结构体
GPIO_InitTypeDef GPIO_Struct;
GPIO_Struct.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Mode_AF_PP
GPIO_Struct.GPIO_Pin = USART_GPIO_PIN_TX ;
GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(USART_GPIO_PORT_TX,&GPIO_Struct);
}
参数详情
GPIO结构体
typedef struct
{
uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
1.GPIO_Mode:
GPIO_Mode_AIN = 0x0, // 模拟输入
GPIO_Mode_IN_FLOATING = 0x04, // 浮空输入
GPIO_Mode_IPD = 0x28, // 下拉输入
GPIO_Mode_IPU = 0x48, // 上拉输入
GPIO_Mode_Out_OD = 0x14, // 开漏输出
GPIO_Mode_Out_PP = 0x10, // 推挽输出
GPIO_Mode_AF_OD = 0x1C, // 复用开漏输出
GPIO_Mode_AF_PP = 0x18 // 复用推挽输出
2.GPIO_Pin:
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */
3.GPIO_speed:
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
GPIO赋值两个函数
// 给对应端口的引脚置1
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BSRR = GPIO_Pin;
}
// 置零
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx->BRR = GPIO_Pin;
}
二.GPIO 初始化按键中断
1.按键时钟和GPIO口宏定义
#define KEY1_INT_GPIO_PIN GPIO_pin_0
#define KEY1_INT_PORT GPIOA
#define KEY1_INT_CLK RCC_APB2Periph_GPIOA
2.初始化按键GPIO
void KEY_GPIO_Config()
{
GPIO_InitTypeDef KEY1_Initstruct;
//gpio
RCC_APB2PeriphResetCmd(KEY1_GPIO_clk,ENABLE);
KEY1_Initstruct.GPIO_Pin = KEY1_GPIO_Pin;
KEY1_Initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_GPIO_PORT,&KEY1_Initstruct);
}
3.初始化EXTI
void KEY_EXTI_Config()
{
EXTI_InitTypeDef EXTI_Initstruct; EXTI结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 打开EXTI时钟使能
GPIO_EXTILineConfig(KEY1_GPIO_PORT, KEY1_GPIO_Pin); 让GPIO的终端线连接0线
EXTI_Initstruct.EXTI_Line = EXTI_Line0; //初始化零线
EXTI_Initstruct.EXTI_Mode = EXTI_Mode_Interrupt; //中断方式是外部中断
EXTI_Initstruct.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发
EXTI_Initstruct.EXTI_LineCmd = ENABLE; // 外设中断使能
EXTI_Init(&EXTI_Initstruct);
}
4.初始化NVIC
void NVIC_Config()
{
NVIC_InitTypeDef NVIC_Initstruct; //��misc.h ��
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_Initstruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Initstruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_Initstruct);
}
注意!!!
在it.c文件中写入中断触发需要执行的函数
我们外设的中断函数名字是已经写好的,我们需要在.s启动文件中找到对应的中断向量表
三.SYsTick 滴答定时器
他是一个24位递减的计数器,内嵌在NVIC中,Core-M3内核都有这个属于硬件中断我们通过调用他的systick_config()函数就可以初始化他了
1.系统定时器结构体
typedef struct
{
/*******
//状态与控制寄存器,可以通过这个寄存器的16位来判断上次的计数值是否为0
//也就是是否完成了计数
********/
__IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */
//装载寄存器,存储的是初值
__IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */
//当前值
__IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */
__I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */
} SysTick_Type;
2.系统定时器初始化
//TICKINT
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
//保护机制,系统定时器的值最大为24位
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);
//给重载寄存器赋初值
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
//设置他的中断优先级
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
//给当前的值赋零
SysTick->VAL = 0;
//初始化状态和控制寄存器
//CLKSOURCE 就是AHB还是 AHB/8 相当于是定时器的频率
//ENABLE 使能
//TICKINT 如果计数完了则会置1 抛异常
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0);
}
3.头文件Sys_Tick.h
#ifndef __SYS_TICK_H
#define __SYS_TICK_H
void Sys_Tick_us(uint32_t us);
void Sys_Tick_ms(uint32_t ms);
#endif
毫秒和微妙函数
void Sys_Tick_us(uint32_t us)
{
uint32_t i;
SysTick_Config(72);
for(i =0;i<us;i++)
{
while(!(SysTick->CTRL & (1<<16)));
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
void Sys_Tick_ms(uint32_t ms)
{
uint32_t i;
SysTick_Config(72000);
for(i =0;i<ms;i++)
{
while(!(SysTick->CTRL & (1<<16)));
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}Sys_Tick_us
四.串口通信
这里我是直接在画图板上总结好了这里直接扔截图过来
1.USART.h
define DEBUG_USART1 1
#define DEBUG_USART2 0
#define DEBUG_USART3 0
#define DEBUG_USART4 0
#define DEBUG_USART5 0
//初始化USART
//1.在STM32.h文件中找USART1
//2.在RCC.h文件中找时钟USART1的时钟
#if DEBUG_USART1
#define DEBUG_USARTx USART1 //在STM32f10x.h中找
#define DEBUG_USART_CLK RCC_APB2Periph_USART1 //在rcc.h中找
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd 这就是个函数昂,之前误会了
#define DEBUG_USART_BAUDRATE 115200
//GPIO_init
#define USART_GPIO_PORT_TX GPIOA
#define USART_GPIO_PIN_TX GP0IO_Pin_9
//在rcc头文件中拉取GPIOA的时钟线
#define USART_GPIO_CLK RCC_APB2Periph_GPIOA
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd ///这就是个函数昂,之前误会了
#define USART_GPIO_PORT_RX GPIOA
#define USART_GPIO_PIN_RX GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn //中断源
#define DEBUG_USART_IRQHandler USART1_IRQHandler //中断执行函数
#elif DEBUG_USART2
#define DEBUG_USARTx USART2
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
#elif DEBUG_USART3
#define DEBUG_USARTx USART3
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
#elif DEBUG_USART4
#define DEBUG_USARTx USART4
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
#elif DEBUG_USART5
#define DEBUG_USARTx USART4
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
#endif
void NVIC_Config_init();
void USART_Config();
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data);
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array,uint8_t num);
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str);
#endif
这里我是用了条件编译,但是其他的串口信息还未更改,大家自行更改就行
2.NVIC初始化USART的中断优先级
void NVIC_Config_init()
{
NVIC_InitTypeDef NVIC_Struct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_Struct.NVIC_IRQChannel = USART1_IRQn;
NVIC_Struct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Struct.NVIC_IRQChannelSubPriority = 1;
NVIC_Struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_Struct);
}
3.配置USART.config
void USART_Config()
{
USART_InitTypeDef Usart_Struct;
GPIO_InitTypeDef GPIO_Struct;
//NVIC
NVIC_Config();
//初始化时钟
DEBUG_USART_GPIO_APBxClkCmd(RCC_APB2Periph_GPIOA ,ENABLE);
DEBUG_USART_APBxClkCmd(RCC_APB2Periph_USART1,ENABLE);
//Usart
Usart_Struct.USART_BaudRate = DEBUG_USART_BAUDRATE; //波特率
Usart_Struct.USART_WordLength = USART_WordLength_8b; //字宽
Usart_Struct.USART_StopBits = USART_StopBits_1; //停止位
Usart_Struct.USART_Parity = USART_Parity_No; //校验位
Usart_Struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //流控制
Usart_Struct.USART_Mode = (USART_Mode_Rx |USART_Mode_Tx);
USART_Init(DEBUG_USARTx, &Usart_Struct);
//GPIO
GPIO_Struct.GPIO_Mode = GPIO_Mode_AF_PP; //这里需要更改
GPIO_Struct.GPIO_Pin = USART_GPIO_PIN_TX ;
GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(USART_GPIO_PORT_TX,&GPIO_Struct);
GPIO_Struct.GPIO_Mode = GPIO_Mode_AF_PP; //这里需要更改
GPIO_Struct.GPIO_Pin = USART_GPIO_PIN_RX ;
GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(USART_GPIO_PORT_RX,&GPIO_Struct);
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE); //少了
// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE); //少了
}
4.串口的收发函数
//字节
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
USART_SendData(pUSARTx, data);
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET );
}
//数组
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array,uint8_t num)
{
uint8_t i;
for( i=0; i<num; i++ )
{
Usart_SendByte(pUSARTx, array[i]);
}
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}
/* 发送字符串 */
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str)
{
uint8_t i=0;
do
{
Usart_SendByte(pUSARTx, *(str+i));
i++;
}while(*(str+i) != '\0');
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}
5.fgutc和fputc
//重定向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);
}
2024年11月3日23:53分
---------------------------------------------------------------------------------------------------------------------------------