自学STM32笔记

IO篇

gpio类型

#define GPIO_MODE_INPUT/*浮空输入模式*/
#define GPIO_MODE_OUTPUT_PP/*推挽输出模式*/
#define GPIO_MODE_OUTPUT_OD/*开漏输出模式*/
#define GPIO_MODE_AF_PP/*复用推挽输出模式*/
#define GPIO_MODE_AF_OD/*复用开漏输出模式*/
#define GPIO_MODE_AF_INPUT/*复用输入模式*/
#define GPIO_MODE_ANALOG /*模拟输入模式*/

#define GPIO_MODE_IT_RISING /*具有上升沿触发检测的外部中断模式*/
#define GPIO_MODE_IT_FALLING /*具有下降沿触发检测的外部中断模式*/
#define GPIO_MODE_IT_RISING_FALLING /*具有上升/下降沿触发检测的外部中断模式*/

#define GPIO_MODE_EVT_RISING /*具有上升沿触发检测的外部事件模式*/
#define GPIO_MODE_EVT_FALLING /*带有下降沿触发检测的外部事件模式*/
#define GPIO_MODE_EVT_RISING_FALLING /*具有上升/下降沿触发检测的外部事件模式*/

中断篇

配置步骤

1、使能时钟
2、设置GPIO工作模式,触发条件,开启AFIO时钟,设置IO口与中断线的映射关系
3、配置中断优先级(NVIC),并使能中断
4、编写中断服务函数
5、编写中断处理回调函数

1-2初始化

	这段要放进main里初始化
	__HAL_RCC_GPIOE_CLK_ENABLE();
	触发条件:
	gpio_init_struct.Mode=GPIO_MODE_IT_FALLING;
	gpio_init_struct.Pin=GPIO_PIN_4;
	gpio_init_struct.Pull=GPIO_PULLUP;
	gpio_init_struct.Speed=GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOE,&gpio_init_struct);

3配置中断优先级

	/* 抢占0,子优先级2 */
    HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 2);  
	/* 使能中断线4 */             
    HAL_NVIC_EnableIRQ(EXTI4_IRQn);                      

4编写中断服务函数

0-4独立,5-9共用,10-15共用
void EXTI4_IRQHandler(void)
{
/* 调用中断处理公用函数 清除KEY0所在中断线 的中断标志位 */
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
/* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);         
}

5编写中断处理回调函数

注意:该函数会自动被4中中断函数调用
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{

}

串口篇

配置步骤

1、串口参数初始化(波特率、字长、奇偶校验等)
2、使能串口和GPIO口时钟
3、GPIO模式设置(速度、上下拉、复用功能等)
4、开启串口相关中断,配置串口中断优先级
5、编写中断服务函数
6、串口数据接收和发送

1、串口参数初始化(波特率、字长、奇偶校验等)

#define USART_REC_LEN               200         /* 定义最大接收字节数 200 */
#define USART_EN_RX                 1           /* 使能(1)/禁止(0)串口1接收 */
#define RXBUFFERSIZE   1                        /* 缓存大小 */

UART_HandleTypeDef g_uart1_handle;       /* HAL UART句柄 */
uint8_t  g_usart_rx_buf[USART_REC_LEN];  /* 接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 */
uint16_t g_usart_rx_sta;                 /* 接收状态标记 */
uint8_t g_rx_buffer[RXBUFFERSIZE];       /* HAL库USART接收Buffer */

void usart_init(uint32_t baudrate)
{
    /*UART 初始化设置*/
    g_uart1_handle.Instance = USART_UX;                                       /* USART_UX */
    g_uart1_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    g_uart1_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    g_uart1_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    g_uart1_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&g_uart1_handle);                                           /* HAL_UART_Init()会使能UART1 */

    /* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */
    HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE); 
}

2-4使能串口和GPIO口时钟

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef gpio_init_struct;

    if (huart->Instance == USART_UX)                            /* 如果是串口1,进行串口1 MSP初始化 */
    {
        __HAL_RCC_USART1_CLK_ENABLE();                          /* 使能串口时钟 */
		__HAL_RCC_GPIOA_CLK_ENABLE();                           /* 使能串口TX、X脚时钟 */

        gpio_init_struct.Pin = USART_TX_GPIO_PIN;               /* 串口发送引脚号 */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽输出 */
        gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* IO速度设置为高速 */
        HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);
                
        gpio_init_struct.Pin = USART_RX_GPIO_PIN;               /* 串口RX脚 模式设置 */
        gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;    
        HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 串口RX脚 必须设置成输入模式 */
        
        HAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */
        HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 组2,最低优先级:抢占优先级3,子优先级3 */
    }
}

5、编写中断服务函数

void USART_UX_IRQHandler(void)
{
    HAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */
}

6、回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART_UX)                    /* 如果是串口1 */
    {
        if ((g_usart_rx_sta & 0x8000) == 0)             /* 接收未完成 */
        {
            if (g_usart_rx_sta & 0x4000)                /* 接收到了0x0d(即回车键) */
            {
                if (g_rx_buffer[0] != 0x0a)             /* 接收到的不是0x0a(即不是换行键) */
                {
                    g_usart_rx_sta = 0;                 /* 接收错误,重新开始 */
                }
                else                                    /* 接收到的是0x0a(即换行键) */
                {
                    g_usart_rx_sta |= 0x8000;           /* 接收完成了 */
                }
            }
            else                                        /* 还没收到0X0d(即回车键) */
            {
                if (g_rx_buffer[0] == 0x0d)
                    g_usart_rx_sta |= 0x4000;
                else
                {
                    g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0];
                    g_usart_rx_sta++;

                    if (g_usart_rx_sta > (USART_REC_LEN - 1))
                    {
                        g_usart_rx_sta = 0;             /* 接收数据错误,重新开始接收 */
                    }
                }
            }
        }

        HAL_UART_Receive_IT(&uart_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
    }
}

7、串口数据接收和发送

中断接收:
 HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
 发送:
 HAL_UART_Transmit(&g_uart1_handle,(uint8_t*)g_usart_rx_buf, len, 1000);
 printf("";
 注意该函数需要重定义
 /* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{
    while ((USART_UX->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */

    USART_UX->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}


加入以下不需要开启Use MicroLIB
#if (__ARMCC_VERSION >= 6010050)            /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t");  /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t");    /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */

#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)

struct __FILE
{
    int handle;
    /* Whatever you require here. If the only file you are using is */
    /* standard output using printf() for debugging, no file handling */
    /* is required. */
};

#endif

/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
    ch = ch;
    return ch;
}

/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{
    x = x;
}

char *_sys_command_string(char *cmd, int len)
{
    return NULL;
}


/* FILE 在 stdio.h里面定义. */
FILE __stdout;

/* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{
    while ((USART_UX->SR & 0X40) == 0);     /* 等待上一个字符发送完成 */

    USART_UX->DR = (uint8_t)ch;             /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}

函数篇

中断服务函数

void EXTI4_IRQHandler(void)//外部中断
{
	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);
}

void USART_UX_IRQHandler(void)//串口中断
{
    HAL_UART_IRQHandler(&g_uart1_handle);   /* 调用HAL库中断处理公用函数 */
}
void WWDG_IRQHandler(void)//串口看门狗
{
    HAL_WWDG_IRQHandler(&g_wwdg_handle);  /* 调用WWDG共用中断处理函数 */
}

中断回调函数

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//外部中断
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)//窗口看门狗

独立看门狗

配置步骤

1、取消寄存器写保护,设置预分频系数和重装载值
2、重载计数值喂狗
3、启动看门狗

1、3、取消寄存器写保护,设置预分频系数和重装载值

由于HAL_IWDG_Init函数中已经有了取消写保护,所以不用额外再写
IWDG_HandleTypeDef g_iwdg_handle;  /* 独立看门狗句柄 */
void iwdg_init(uint8_t prer, uint16_t rlr)
{
    g_iwdg_handle.Instance = IWDG;
    g_iwdg_handle.Init.Prescaler = prer; /* 设置IWDG分频系数 */
    g_iwdg_handle.Init.Reload = rlr;     /* 重装载值 */
    HAL_IWDG_Init(&g_iwdg_handle);       /* 初始化IWDG并启动 */
}

2、重载计数值喂狗

HAL_IWDG_Refresh(&g_iwdg_handle);  /* 重装载计数器 */

计算

分频64,重装值625,时间大约是1s
则频率应该是40k,则(1/40k)64=0.0016s
重装值625
0.0016=1s

窗口看门狗

配置步骤

1、使能时钟
2、设置窗口值,分频数和计算器初始值
3、开启wwdg
4使能中断通道并配置优先级(如果开启了wwdg中断)
5、编写中断服务函数
6、重写串口看门狗唤醒中断处理回调函数

23初始化

WWDG_HandleTypeDef g_wwdg_handle;  /* WWDG句柄 */
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t fprer)
{
    g_wwdg_handle.Instance = WWDG;
    g_wwdg_handle.Init.Prescaler = fprer;         /* 设置分频系数 */
    g_wwdg_handle.Init.Window = wr;               /* 设置窗口值 */
    g_wwdg_handle.Init.Counter = tr;              /* 设置计数器值 */
    g_wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE; /* 使能窗口看门狗提前唤醒中断 */
    HAL_WWDG_Init(&g_wwdg_handle);                /* 初始化WWDG */
}
Fwwdg=PCLK1/(4096*2^fprer). 一般PCLK1=36Mhz

14

void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
    __HAL_RCC_WWDG_CLK_ENABLE();            /* 使能窗口看门狗时钟 */

    HAL_NVIC_SetPriority(WWDG_IRQn, 2, 3);  /* 抢占优先级2,子优先级为3 */
    HAL_NVIC_EnableIRQ(WWDG_IRQn);          /* 使能窗口看门狗中断 */
}

5中断服务函数

void WWDG_IRQHandler(void)
{
    HAL_WWDG_IRQHandler(&g_wwdg_handle);  /* 调用WWDG共用中断处理函数 */
}

6回调函数

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
    HAL_WWDG_Refresh(&g_wwdg_handle); /* 更新窗口看门狗值 */
    LED1_TOGGLE();                    /* LED1闪烁 */
}

在这里插入图片描述

基本定时器

对于STM32F103RET6
基本定时器6、7;
通用定时器2、3、4、5;
高级定时器1、8;

配置步骤

1、定时器使能
2、初始化定时器参数、设置自动重装值,分频系数,计数方式
3、使能定时器中断,开启定时器计数,配置定时器中断优先级
4、编写中断服务函数

2初始化

TIM_HandleTypeDef g_timx_handle;  /* 定时器句柄 */

void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
    g_timx_handle.Instance = TIM6;                      /* 通用定时器X */
    g_timx_handle.Init.Prescaler = 7200-1;                          /* 设置预分频系数 */
    g_timx_handle.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
    g_timx_handle.Init.Period = 5000-1;                             /* 自动装载值 */
    HAL_TIM_Base_Init(&g_timx_handle);

    HAL_TIM_Base_Start_IT(&g_timx_handle);    /* 使能定时器x及其更新中断 */
}

13使能中断

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM6)
    {
       __HAL_RCC_TIM6_CLK_ENABLE();                  /* 使能TIM时钟 */
        HAL_NVIC_SetPriority(TIM6_IRQn, 1, 3); /* 抢占1,子优先级3,组2 */
        HAL_NVIC_EnableIRQ(TIM6_IRQn);         /* 开启ITM3中断 */
    }
}

中断服务函数

void TIM6_DAC_IRQHandler(void)
{
	HAL_TIM_IRQHandler(&g_timx_handle);
}

中断回调函数


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM6)
	{
		LED1_TOGGLE();
	}
}

通用定时器

注意!!!

1、基本定时器用TIM6_DAC_IRQHandler,但是到了通用定时器就变了,而是TIM2_IRQHandler.
2、看代码
void TIM2_IRQHandler(void)
{
LED1_TOGGLE();
__HAL_TIM_CLEAR_FLAG(&tim2_handle,TIM_IT_UPDATE);	
}
这个直接在中断服务函数处理了,所以这里需要手动清除标志
使用回调函数时会自动清理标志。

PWM

配置步骤

1、开启定时器、通道输出的时钟,配置该IO口复用
2、初始化tim,设置arr、psc等参数
3、设置timx_CHy的PWM函数,输出比较极性、比较值等参数。
4、使能timx,使能tim chy输出
5、修改timx——ccr2来控制占空比

直接上代码

	TIM_HandleTypeDef g_timx_pwm_chy_handle;     /* 定时器x句柄 */
	TIM_OC_InitTypeDef timx_oc_pwm_chy  = {0};                          /* 定时器PWM输出配置 */

    g_timx_pwm_chy_handle.Instance = TIM3;                     /* 定时器x */
    g_timx_pwm_chy_handle.Init.Prescaler = 72;                         /* 定时器分频 */
    g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;        /* 递增计数模式 */
    g_timx_pwm_chy_handle.Init.Period = 500;                            /* 自动重装载值 */
    HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);                           /* 初始化PWM */

    timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1;                           /* 模式选择PWM1 */
    timx_oc_pwm_chy.Pulse = 250;                                    /* 设置比较值,此值用来确定占空比 */
                                                                        /* 默认比较值为自动重装载值的一半,即占空比为50% */
    timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_LOW;                    /* 输出比较极性为低 */
    HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, TIM_CHANNEL_2); /* 配置TIMx通道y */
    HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_2);       /* 开启对应PWM通道 */


    while (1)
    {
		
		delay_ms(10);
		if(flag1==0)
		{
			if(++num==300)
			{
				flag1=1;
			};
		}
		else{
			if(--num==0)
			{
				flag1=0;
			}
		}
		__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle,TIM_CHANNEL_2,num);

    }

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM3)
	{
		GPIO_InitTypeDef gpio_init_struct;
		__HAL_RCC_GPIOB_CLK_ENABLE();
		__HAL_RCC_TIM3_CLK_ENABLE();
		
		gpio_init_struct.Pin = GPIO_PIN_5;
		gpio_init_struct.Mode = GPIO_MODE_AF_PP;
		gpio_init_struct.Pull = GPIO_PULLUP;
		gpio_init_struct.Speed = GPIO_SPEED_HIGH;
		HAL_GPIO_Init(GPIOB,&gpio_init_struct);
		__HAL_RCC_AFIO_CLK_ENABLE();

		__HAL_AFIO_REMAP_TIM3_PARTIAL();
	}
}


定时器捕获

配置步骤

1、开启tim和输入通道gpio时钟,配置该io口复用功能输入
2、初始化tim,设置tim的arr、psc
3、设置timx_chy输入捕获模式,开启输入捕获
4、使能定时器中断,开启捕获功能以捕获中断,配置定时器中断优先级
5、编写中断服务函数

算了不写了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

略不世出

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值