STM32+CubeMX+Keil+HAL库

 

目录

1. 设置GPIO:

 2. printf重定向

3. Log信息格式

4. 个性化输出

5. CubeMX+HAL打开串口中断

 6. 打开外部中断

7. 时钟树基本操作

8. 通用定时器配置

9. CubeMX配置定时器

(1)将定时器的时钟设为72M

 (2)选择内部时钟

 (3)配置定时器

 (4)开启中断

 定时器中断回调函数:(平滑滤波)

10. CubeMX配置pwm

11. CubeMX配置spwm

12. CubeMX配置ADC

(1)轮询

(2)DMA方式

13. IIC和SPI


STM32系列视频(CubeMX+MDK5+HAL库+库函数一站式学习)_哔哩哔哩_bilibili

1. 设置GPIO:

(1)将PA8设置为输出,推挽上拉,初始状态为高电平:

 (2)使用pin configuration里边的User Label,可以生成对应的宏,提高代码的复用性,并且方便移植。

 在对应的工程代码里就会有如下所示的宏定义:

 2. printf重定向

int fputc(int ch, FILE *f)
{
	uint8_t temp[1] = {ch};
	HAL_UART_Transmit(&huart1, temp, 1, 2);
	return ch;
}

3. Log信息格式

参考目前主流嵌入式、安卓等输出方式:

[日志级别] 文件名 : 日志信息
//例: [info] main.c : init ok!
//例: [debug] adc.c : adc_getvalue -> 3.3v

(1)可以使用条件编译的方式来决定是否打印Log信息:

#define Log   1  //不想打印时改为 0 即可


#if Log
printf("[info]main.c:init!\r\n");
#endif

(2)可变参数宏

#define USER_MAIN_DEBUG


#ifdef USER_MAIN_DEBUG


#define user_main_printf(format, ...) printf( format "\r\n",##__VA_ARGS__)

#define user_main_info(format, ...) printf("【main】info:" format "\r\n",##__VA_ARGS__)

#define user_main_debug(format, ...) printf("【main】debug:" format "\r\n",##__VA_ARGS__)

#define user_main_error(format, ...) printf("【main】error:" format "\r\n",##__VA_ARGS__)

#else

#define user_main_printf(format, ...)

#define user_main_info(format, ...) 

#define user_main_debug(format, ...)

#define user_main_error(format, ...)

#endif

当我需要打印串口信息时,define一个USER_MAIN_DEBUG,在我不需要时就将其注释。

4. 个性化输出

可以借助这个网站来设计字符:http://patorjk.com/software/taag/

printf(".__           .__  .__                            .__       .___");
printf("|  |__   ____ |  | |  |   ______  _  _____________|  |    __| _/");
printf("|  |  \\_/ __ \\|  | |  |  /  _ \\ \\/ \\/ /  _ _  __ \\  |   / __ | ");
printf("|   Y  \\  ___/|  |_|  |_(  <_> )     (  <_> )  | \\/  |__/ /_/ | ");
printf("|___|  /\\___  >____/____/\\____/ \\/\\_/ \\____/|__|  |____/\\____ |");
printf("     \\/     \\/                                               \\/");

5. CubeMX+HAL打开串口中断

 

 6. 打开外部中断

另外,EXTI外部中断的GPIO配置如下:默认下拉,上升沿触发。

然后编写外部中断的回调函数即可。

eg:测量pwm的频率

1s的时间内,上升沿的次数就是频率。也就是说,1s内进入外部中断的次数就是频率。每进一次中断,pwm_value加1,1s后它的值就是频率。

当有上升沿时,就进入外部中断将pwm_value的值加1。

int pwm_value = 0;

int main()
{
    pwm_value = 0;
    HAL_Delay(1000);   # 延时1s后得到的pwm_value就是频率值
    printf("[\tmain]info:pwm_value = %d\r\n", pwm_value);
}

# 外部中断的回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == PWM_Pin)     # 判断触发的引脚是否是定义的引脚   
    {
        pwm_value++;
    }
}

7. 时钟树基本操作

(1)使能外部时钟源

一般情况下,生成的工程默认用的是内部时钟,所以先进行外部时钟的使能。

 (2)然后将HCLK时钟频率调到最大,例如f103最大是72M,而f406最大是84M。

 (3)最后,针对不同的外设进行按需分频。

8. 通用定时器配置

eg:特定时间翻转LED。

# 溢出时间
Tout = (arr+1)*(psc+1)/Tclk
频率:Tclk/(psc+1) MHz

void Timer3_Init(uint16_t arr,uint16_t psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_Trigger,ENABLE);   //定时器中断使能

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;  //先占优先级1级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设					 
}

void TIM3_IRQHandler(void)   //TIM3中断
{
    static uint8_t cnt = 0;    //静态变量
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
    {
        /*中断操作*/
        cnt++;
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 
	}
    if(cnt == 10)
    {
        LED = ~LED;
        cnt = 0;
    }
}

9. CubeMX配置定时器

(1)将定时器的时钟设为72M

 (2)选择内部时钟

 (3)配置定时器

主要配置:定时时间,以及是否重装定时器。

定时频率 = 定时器时钟/(预分频 + 1)/(计数值 + 1)Hz。

定时时间 = 1/定时频率  s。

 (4)开启中断

基本定时器:

高级定时器:

 定时器中断回调函数:(平滑滤波)

eg:平滑滤波 -- 让采样值在另一个“线程”一直滤波,而在需要它的时候,直接取它的值即可。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == htim1.Instance)
    {
        pwm_sum += pwm_value * 10;  //pwm_sum累加
        pwm_sum -= pwm_avg;         //pwm_sum减去上次的平均值
        pwm_avg = pwm_sum * 1.0 / 5; //更新pwm的平均值
        pwm_value_final = pwm_avg;   //pwm_value_final的值即为当前pwm的频率
        pwm_value = 0;               //将pwm_value清空,重新计数
    }
}

10. CubeMX配置pwm

(1)使能PWM通道

 这里,将TIM2的Channel1设置为PWM输出通道。

(PWM Generation CHx 正向、PWM Generation CHxN 反向、 PWM Generation CHx CHxN 一对互补 pwm 输出)

(2)配置频率及占空比

频率 = 定时器时钟 / (Prescaler + 1) / (Cound Period + 1) Hz

占空比 = Pulse(对比值) / (Cound Period 计数值) %

 (3)下属代码实现了pwm占空比逐渐增大至1,然后变为0的一个过程。

int main(void)
{
    int pwm = 0;
  
    HAL_Init();

  /* Configure the system clock */
    SystemClock_Config();

  /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_TIM1_Init();

    # 使能tim1的通道1
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

    while (1)
    {
        HAL_Delay(5);
        # 修改tim1的通道1的pwm比较值为pwm++,即修改占空比
        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwm++);
        pwm = (pwm > 999) ? 0:pwm;
    }
}

11. CubeMX配置spwm

SPWM就是在PWM的基础上,让PWM的占空比做正弦变化。

STM32系列视频(CubeMX+MDK5+HAL库+库函数一站式学习)_哔哩哔哩_bilibili

略。

12. CubeMX配置ADC

通常是12位,精度为3.3/4096 v。

读取ADC的方式:轮询、DMA。

(1)轮询

首先配置ADC1的CH0,并且使能连续采集。

while(1)
{
    HAL_ADC_Start(&hadc1);//启动ADC装换
    HAL_ADC_PollForConversion(&hadc1, 50);//等待转换完成, 第二个参数表示超时时间,单位ms.
    if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
    { 
        AD_Value = HAL_ADC_GetValue(&hadc1);//读取ADC转换数据, 数据为12位
        printf("[\tmain]info:v=%.1fmv\r\n",AD_Value*3300.0/4096);//打印日志
    }
}

(2)DMA方式

① 初始化两个ADC通道

 ② 配置

使能连续转换模式(Continuous Conversion Mode);

ADC规则组选择转换通道数为2(Number Of Conversion);

配置Rank的输入通道,分别转换channel 0和channel 1。

③ 添加DMA

设置为连续传输模式,数据长度为字。

 ④ 示例代码

数组偶数下标的数据为通道0采集数据,数组奇数下标的数据为通道1采集数据。

程序中将数组偶数下标数据加起来求平均值,实现均值滤波的功能,再将数据转换为电压值,即为PA0管脚的电压值。另一个通道同理。

uint32_t ADC_Value[100];  //数据缓存数组
uint8_t i;
uint32_t ad1, ad2;  //ad1存储PA0的电压值;ad2存储PA1的电压值

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM1_Init();
  MX_DMA_Init();
  MX_ADC1_Init();

  HAL_TIM_Base_Start_IT(&htim1);
# 以DMA方式开启ADC转换。第二个参数是数据存储起始地址,第三个参数是DMA传输数据的长度。
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 100);  
  while (1)
  {
    HAL_Delay(500);
    for(i = 0,ad1 =0,ad2=0; i < 100;)
    {
        ad1 += ADC_Value[i++];
        ad2 += ADC_Value[i++];
    }
    ad1 /= 50;
    ad2 /= 50;
    printf("\r\n********ADC-DMA-Example********\r\n");
    printf("[\tmain]info:AD1_value=%1.3fV\r\n", ad1*3.3f/4096);
    printf("[\tmain]info:AD2_value=%1.3fV\r\n", ad2*3.3f/4096);
  }

13. IIC和SPI

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: AD9910是一款数字频率合成器芯片,常用于射频通信、雷达、无线传感器网络等领域。HAL库是针对STM32系列微控制器提供的硬件抽象层,通过使用HAL库可以方便地对硬件进行初始化和配置。下面是关于如何使用HAL库配置AD9910的方法: 首先,在STM32微控制器中连接AD9910芯片。可以选择SPI接口进行通信,通过设置STM32的SPI相关寄存器来配置SPI通信参数。具体的SPI通信参数包括数据位长度、CPOL、CPHA、时钟分频等。 其次,通过HAL库函数设置GPIO引脚的模式和电平。根据AD9910的引脚连接表,选择相应的引脚作为输出控制信号,通过HAL库提供的函数设置为输出模式,并设置合适的电平。 接着,使用HAL库函数初始化SPI接口,并设置合适的时钟频率、传输模式等参数。可以通过调用HAL_SPI_Init函数进行初始化。 然后,通过HAL库函数发送配置指令和数据到AD9910芯片。可以通过调用HAL_SPI_Transmit函数来发送命令和数据,将需要配置的寄存器地址和对应的配置值发送给AD9910。可以根据AD9910的寄存器映射表确定寄存器地址和配置值。 最后,检查配置是否生效。可以通过读取AD9910的状态寄存器,或者使用HAL库函数读取AD9910的寄存器值来验证配置是否正确。 总结起来,通过HAL库配置AD9910主要包括SPI接口的配置、GPIO引脚的设置、SPI接口的初始化和通过SPI发送配置数据到AD9910等步骤。通过合理使用HAL库函数,可以方便地完成AD9910的硬件配置。 ### 回答2: AD9910是一款高性能的直接数字合成频率器件,使用HAL库配置是指使用STM32HAL库进行AD9910的初始化和配置。下面是使用HAL库配置AD9910的步骤: 1. 软件开发环境准备:首先需要搭建好STM32开发环境,包括安装好Keil MDK和CubeMX软件。 2. 在CubeMX中配置引脚:打开CubeMX软件,选择对应的STM32型号,然后在引脚配置界面将AD9910的控制引脚与STM32的GPIO引脚进行相连接。 3. 配置SPI接口:在CubeMX的配置界面中,选择相应的SPI接口,并设置好通信参数,如时钟频率、数据位数等。 4. 初始化SPI接口:在Keil MDK中编写代码,在main函数中初始化SPI接口,使用HAL_SPI_Init函数进行初始化。 5. 配置AD9910寄存器:根据AD9910的手册和寄存器说明,将需要配置的寄存器值写入到对应的寄存器中。可以使用HAL库提供的函数HAL_SPI_Transmit进行SPI数据传输。 6. 配置AD9910的功能:根据具体需求,配置AD9910的功能,如设置频率、相位、幅度等。可以使用HAL库提供的函数HAL_SPI_Transmit进行SPI数据传输。 7. 发送配置命令:将配置好的寄存器值通过SPI接口发送给AD9910,以实现对AD9910的配置。 8. 验证配置结果:通过读取AD9910的状态寄存器或输出信号,验证AD9910是否按要求进行了配置。 总之,使用HAL库配置AD9910需要在软件开发环境中进行相关配置,然后使用HAL库提供的函数对AD9910进行初始化和配置。最后需要验证配置结果以确保AD9910按预期工作。 ### 回答3: 要配置hal库来控制AD9910,需要遵循以下步骤: 1. 首先,打开STM32HAL库并包含所需的头文件。这些头文件包括stm32f4xx_hal.h、stm32f4xx_hal_spi.h、stm32f4xx_hal_gpio.h等。 2. 然后,初始化SPI总线并设置必要的SPI参数。这些参数包括SPI模式、数据大小、时钟极性和相位等。 3. 接下来,根据AD9910的数据手册配置SPI相关的GPIO引脚,例如片选引脚和时钟引脚。 4. 使用HAL库提供的函数,通过SPI总线发送配置数据到AD9910芯片。这些数据可以是频率、相位、振幅等。 5. 最后,使用HAL库提供的函数在AD9910芯片上产生触发或时钟信号,以启动所配置的频率、相位或振幅。 需要注意的是,配置AD9910的具体步骤可能会有所不同,具体取决于使用的开发板和HAL库版本。因此,请仔细阅读AD9910的数据手册并参考HAL库的相关文档来正确配置AD9910

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值