STM32学习笔记(二)驱动程序

ADC

根据引脚勾选通道

image

参数只需更改采样周期,其它默认即可

image

uint16_t ADC_IN_1(void) //ADC采集程序
{
	HAL_ADC_Start(&hadc1);//开始ADC采集
	HAL_ADC_PollForConversion(&hadc1,500);//等待采集结束
	if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))//读取ADC完成标志位
	{
		return HAL_ADC_GetValue(&hadc1);//读出ADC数值
	}
	return 0;
}
HAL_ADCEx_Calibration_Start(&hadc1);//ADC采样校准
uint16_t adc_num;
adc_num =  ADC_IN_1();

ADC读出的值为0-4096,对应0-3.3V

OLED屏幕SSD1306

开启I2C

image

复制fonts.h、ssd1306.h到Core/Inc目录,复制fonts.c ssd1306.c到Core/Src目录
ssd1306.7z

头文件

#include "fonts.h"
#include "ssd1306.h"

初始化

  SSD1306_Init();
  char snum[5];

主循环中

	for ( int x = 1; x <= 10000 ; x++ )
	{
		itoa(x, snum, 10);
		SSD1306_GotoXY (30, 30);  // 4 DIGIS
		SSD1306_Puts (snum, &Font_16x26, 1);
		SSD1306_UpdateScreen();
		HAL_Delay (500);
	}

定时器

定时时间计算公式:

\text {定时时间(us)}=(\text {计数周期}+1) \times(\text {分频系数}+1) \div \text {时钟频率}

image

根据定时器时钟的频率,比如时钟的频率是72MHZ,可以理解为一秒钟STM32会自己数72M次,预分频系数就是将频率分割,比如分频系数是72,则该时钟的频率会变成72MHZ/72=1MHZ,但是在设置的时候要注意,数值应该是72-1。假定分频系数是72-1,那么频率变成1MHZ,也就意味着STM32在一秒钟会数1M次,即1us数一次。

接下来就是确定预装载值,比如需要定时1ms,由于1ms=1us*1000,那么预装载值就是1000-1;如此类推,在预分频系数确定的情况下,定时的时长就由预装载值确定了。

例如:

image

image

开启定时器

HAL_TIM_Base_Start_IT(&htim2);

回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
	if(htim==(&htim2)){
		LED_1_Contrary();
	}
}

获取定时器计数值

__HAL_TIM_GET_COUNTER(&htim);

AS5600

设置好i2c之后,就可以用了

as5600.7z
AS5600.pdf

w25q128

  1. 设置SPI,这些参数是芯片规定的

    image

    image

  2. 片选引脚设置

    image

  3. 复制驱动程序

  4. 依赖delay_us函数,把delay驱动程序也复制进来

  5. 引入头文件

#include "../../icode/w25q128/w25qxx.h"
  1. 初始化
  HAL_Dalay(500);
  W25QXX_Init();
  1. main
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  if(KEY_1()){
		  EX_FLASH_BUF[0] = W25QXX_ReadID();
		  printf("芯片ID:%x \n\r",EX_FLASH_BUF[0]);
	  }

	  if(KEY_2()){
		  W25QXX_Read(EX_FLASH_BUF,EX_FLASH_ADD,1);
		  EX_FLASH_BUF[0]++;
		  if(EX_FLASH_BUF[0]>200)EX_FLASH_BUF[0]=0;
		  W25QXX_Write(EX_FLASH_BUF,EX_FLASH_ADD,1);
		  printf("读出0x00地址数据:%d \n\r",EX_FLASH_BUF[0]);
	  }

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
  1. 结果
    image

w25q128.7z

延时函数

HAL库的延时函数HAL_Delay()有两个问题:

  1. HAL_Delay不能在中断回调中使用
  2. 最小的延时单位为毫秒,无法延时更小

所以需要自己写一个延时函数:

void delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数
{
    uint32_t delay = (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值,经算法得到1微秒的循环次数
    while (delay--); //循环delay次,达到1微秒延时
}

外部中断

  1. 配置连接按键的引脚为外部中断输入引脚

image

image

  1. 触发中断后,回调函数保存在stm32f1xx_it.c文件中
    image

    这个函数中调用了一个叫HAL_GPIO_EXTI_IRQHandler的函数,在HAL_GPIO_EXTI_IRQHandler中又调用了一个以__weak前缀开头的函数

image

以__weak开头的函数,如果我们没有实现它,就执行他,如果我们声明了一个同名函数,就以我们的为准。

所以我们只需要定义一个

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  1. main.c文件中
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
	if(GPIO_Pin == KEY1_Pin){
		LED_1_Contrary();
	}
}
  1. 注意
    HAL_Delay延时函数不能在中断回调中使用,所以我们需要将所有用的HAL_Delay的地方换成我们自己写的delay_us()

LED与KEY驱动程序

  1. 在STM32CubeMX中设置对应引脚的模式

image


void LED_1(uint8_t a)//LED1独立控制函数(0为熄灭,其他值为点亮)
{
	if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);
	else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);
}


uint8_t KEY_1(void)
{
	uint8_t a;
	a=0;
	if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){
		//HAL_Delay(20);
		delay_us(2000);
		if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET){ 
			a=1;
		}
	}
	while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)==GPIO_PIN_RESET);
	delay_us(2000);
	return a;
}

PWM

image

周期的设置方法与定时器相同,

\text {定时时间(us)}=(\text {计数周期}+1) \times(\text {分频系数}+1) \div \text {时钟频率}

image

  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
  /* USER CODE END 2 */
	while (pwmVal< 500)
	{
	  pwmVal++;
	  __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwmVal);
	  HAL_Delay(1);
	}
	while (pwmVal)
	{
	  pwmVal--;
	  __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwmVal);
	  HAL_Delay(1);
	}
	HAL_Delay(200);

串口printf

  1. 在STM32CubeMX中设置串口的模式

image

  1. 排除syscalls.c

    image

  2. 把retarget.h拷贝到Core/Inc,把retarget.c拷贝到Core/Src

  3. 头文件引入

#include "../inc/retarget.h"
  1. 初始化
RetargetInit(&huart1);
  1. 主程序
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  if(KEY_1()){
		  printf("KEY1\r\n");
	  }

	  if(KEY_2()){
		  printf("KEY2\r\n");
	  }

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
  1. 烧录程序后,需要关闭FlyMcu,然后再打开超级终端,因为这两个程序都用串口,有冲突。按键后在会在屏幕上打印信息
    image

retarget.7z

posted @ 2024-05-19 05:24:18
评论加载中...
发表评论