Stm32CubeMX学习笔记

您所在的位置:网站首页 stm32两个串口 Stm32CubeMX学习笔记

Stm32CubeMX学习笔记

2023-06-23 16:57| 来源: 网络整理| 查看: 265

本文内容结合个人开发经验和其他博主的见解,供个人学习使用

----待更新----

文章目录 ----待更新----系统选择芯片配置时钟、调试模式√中断优先级NVIC√生成code√ GPIO -外部中断定时器定时器中断√PWM模式√编码器模式√ ADC单通道轮询√多通道轮询√ 串口√串口发送串口接收中断

系统 选择芯片 配置时钟、调试模式√

1.设置使用外部高速时钟源(8M晶振) 在这里插入图片描述如果使用RTC时钟,要使能LSE。 说明: BYPASS Clock Source(旁路时钟源) Crystal/Ceramic Resonator(石英/陶瓷 晶振)

2.设置时钟树为72M 修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置 在这里插入图片描述

3.调试模式为SW模式

中断优先级NVIC√

NVIC即嵌套向量中断控制器,用于配置各种中断源的使能和失能,响应优先级。 除了在此处配置,在具体中断功能中的NVICsetting选项卡中也可以设置并自动保持同步。 在这里插入图片描述

Preemption Priority:抢占优先级 Sub Priority:子优先级(响应优先级) 数字越小表示优先级越高

在CubeMX中默认只有抢占优先级可以进行0-15的设置,响应优先级只能为0,可以自行设置中断优先级控制位分组,分配如下:

编号分配情况说明0/1/2/34:016抢占优先级,0 子优先级43:18 抢占优先级,2 子优先级52:24 抢占优先级,4 子优先级61:32 抢占优先级,8 子优先级70:40 抢占优先级,16子优先级

多个中断同时响应时,抢占优先级高的会先于抢占优先级低的执行;如果抢占优先级相同,就比较响应优先级;如果响应优先级也相同,就比较它们的硬件中断编号,编号越小优先级越高。 如果在此之前还有一个响应优先级低的还在进行,那么高的响应优先级必须等待低的先进行。

生成code√

1.工程名称,路径,编译器设置 注意工程名和路径要避免使用中文 在这里插入图片描述2.代码生成设置 在这里插入图片描述

GPIO -

GPIO 8 种工作模式

GPIO_Mode_AIN 模拟输入 GPIO_Mode_IN_FLOATING 浮空输入 GPIO_Mode_IPD 下拉输入 GPIO_Mode_IPU 上拉输入 GPIO_Mode_Out_OD 开漏输出 GPIO_Mode_Out_PP 推挽输出 GPIO_Mode_AF_OD 复用开漏输出 GPIO_Mode_AF_PP 复用推挽输出

1、上拉输入、下拉输入可以用来检测外部信号;例如,按键等; 2、浮空输入模式,由于输入阻抗较大,一般把这种模式用于标准通信协议的I2C、USART 的接收端; 3、普通推挽输出模式一般应用在输出电平为 0 和 3.3V 的场合。 普通开漏输出模式一般应用在电平不匹配的场合,如需要输出 5V 的高电平,就需要在外部一个上拉电阻,电源为 5V,把 GPIO 设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出 5V 电平。 4、对于相应的复用模式(复用输出来源片上外设),则是根据 GPIO 的复用功能来选择,如 GPIO 的引脚用作串口的输出(USART/SPI/CAN),则使用复用推挽输出模式。如果用在 I2C、SMBUS 这些需要线与功能的复用场合,就使用复用开漏模式。 5、在使用任何一种开漏模式时,都需要接上拉电阻。

业务代码

//读取电平状态 GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); //设置引脚状态 void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); //转换引脚状态 void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); //锁定引脚状态 HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); //举例: //读取PA0引脚状态 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); //将PA0引脚状态改为低电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);

user lable位于main.h

外部中断 定时器 定时器中断√

1.配置定时器 在这里插入图片描述中断间隔T = (arr+1)(psc+1) / 72M 其中72M 为时钟树设置的主频

2.开启中断 高级定时器勾选update interrupt,普通定时器勾选global interrupt 这里在系统NVIC中配置也是可以的 在这里插入图片描述

3.业务代码 在主函数添加初始化代码

//__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_UPDATE);//如果不想使能中断后立即进入中断,加上这一句 HAL_TIM_Base_Start_IT(&htim1);//开启定时器1中断

重写中断回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim->Instance == htim1.Instance) { } }

完成!

PWM模式√

频率 = 定时器时钟 / (psc预分频 + 1)/ (arr计数值 + 1)Hz 占空比 = ccr ( 对比值) / (arr计数值)% 驱动电机的频率一般10K左右,太低,电机有噪音;太高,功率管无法承受且给电路板带来高频干扰。占空比控制精度一般1000合适。 PWM模式1,有效电平为高,即直观上的ccr体现占空比

1.PWM配置 在这里插入图片描述无需中断,不需要配置中断优先级

2.业务代码

// 使能tim8的通道 HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_1); // 修改tim8的通道1的pwm比较值为pwmval,即修改占空比 __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_1, pwmval);

完成!

编码器模式√

在这里插入图片描述编码器为AB相,用两路输入,编码模式设置为 Encoder Mode TI1 and TI2 则会默认检测AB相的上升沿与下降沿。每一个上升沿和下降沿都触发计数,所以每转一格计数器就会+4/-4。可以将PSC的值改为4-1,就是原脉冲数 在这里插入图片描述 配置定时器两个GPIO引脚模式,全部改成Pull-Up,即上拉模式,用于没有外部上拉的编码器读取时,可以确定引脚电平,防止出错。

在这里插入图片描述 业务代码: 主函数初始化代码,两个通道都要使能

HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_1); HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_2);

测速

//__HAL_TIM_IS_TIM_COUNTING_DOWN(htim); //读取电机转动方向,用不到 //测速函数,short强制转换用于转换负值 int encoder_get(TIM_HandleTypeDef *htim) { int sp=0; sp =(short)__HAL_TIM_GET_COUNTER(htim); __HAL_TIM_SET_COUNTER(htim,0); return sp; } //定时器中断50ms调用 tim_it_50ms() { speed = encoder_get(&htim2);//视情况加正负号 }

完成!

ADC

单通道、多通道 轮询、中断、DMA 轮询方式是阻塞式采集

开启连续模式(Continuous Conversion Mode)后,每次转换完成要调用HAL_ADC_Stop来关闭ADC,好处是可以开启一次ADC,进行多次重复采集。 例如,如果是单通道,非连续模式在完成一次ADC转换后就停止了,而连续模式会一直转换,如果是多通道AN1 ,AN2,AN3,单次转换模式会在三个通道转换完一次后停止,而连续转换模式在转换完AN3后,会从新再次去转换。

单通道轮询√

在这里插入图片描述 业务代码

void ADC_Get() { HAL_ADC_Start(&hadc1); if(HAL_ADC_PollForConversion(&hadc1,50)==HAL_OK)//等待转换完成,第二个参数表示超时时间,单位ms { ADC_Value = HAL_ADC_GetValue(&hadc1); ADC_Volt = ADC_Value * 3.3 / 4096.0; } HAL_ADC_Stop(&hadc1);//若关闭连续模式,可去掉此句 } 多通道轮询√

在这里插入图片描述多个通道时必须开启间断模式(Discontinuous Conversion Mode),并且每个间断组中只有一个通道,否则每次只能读取到每组最后一个通道的值。后面还需设置设置通道转换顺序。

在多通道里面,第一此启用一次ADC的转换是采的第一个通道的(这里第一个通道是channel0);然后是第二个通道(channel1);第三次采又回到了第一个通道(channel0),依次类推。HAL_ADC_Start必须放在for循环中,否则只能采集第一个通道的ADC值。

uint16_t adc1_value[30]; //ADC多通道读取函数,num为通道数,阻塞式读取 void ADC_Get(uint8_t num) { int i=0; for(i=0;i int k=0; do { HAL_UART_Transmit(&huart1,(uint8_t * )(str+k),1,0xffff); k++; } while(*(str+k)!='\0'); return; }

注意发送函数的字节数一定要核实!过大可能导致修改其他地址的数据!!!

或者重新定义printf函数来发送:

//包含头文件 #include //在 USER CODE BEGIN 0 添加以下代码 //函数功能: 重定向c库函数printf到DEBUG_USARTx int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff); return ch; } //函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx int fgetc(FILE *f) { uint8_t ch = 0; while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) == RESET);//等待串口输入数据 HAL_UART_Receive(&huart1, &ch, 1, 0xffff); return ch; }

在keil勾选微库选项(必须勾选,但可能导致运行速度变慢) 在这里插入图片描述然后就可以使用Printf函数和scanf,getchar函数

串口接收中断

函数流程: HAL_UART_Receive_IT(中断接收函数) -> USART2_IRQHandler(void)(中断服务函数) -> HAL_UART_IRQHandler(UART_HandleTypeDef *huart)(中断处理函数) -> UART_Receive_IT(UART_HandleTypeDef *huart) (接收函数) -> HAL_UART_RxCpltCallback(huart);(中断回调函数)

1.添加定义

//添加头文件 #include //添加定义 #define RXSTRSIZE 256 //最大接收字节数 uint8_t rx_string[RXSTRSIZE]; //接收字符串数组 uint8_t rx_cnt=0; //接收字符串计数 uint8_t rx_buff; //接收缓存

2.在主函数初始化处,调用一次接收中断函数

//中断接收1个字符,存储到rx_buff中 HAL_UART_Receive_IT(&huart1, (uint8_t *)&rx_buff, 1); //开启接收中断

3.重写中断回调函数 回调函数中要调用一次HAL_UART_Receive_IT函数,使得程序可以重新触发接收中断

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart -> Instance == huart1.Instance) { //以下是串口接收中断业务代码 if(rx_cnt >= RXSTRSIZE - 1) //溢出判断 { rx_cnt = 0; memset(rx_string,0x00,sizeof(rx_string)); HAL_UART_Transmit(&huart1, (uint8_t *)"overfull!", 10,0xFFFF); } else { rx_string[rx_cnt++] = rx_buff; //接收数据转存 if(rx_string[rx_cnt-1] == 0x0A || rx_string[rx_cnt-2] == 0x0D) //判断结束位,0x0D是回车/r,0x0A是换行\n { HAL_UART_Transmit(&huart1, (uint8_t *)&rx_string, rx_cnt,0xFFFF); //将收到的信息发送出去 while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); //判断发送是否完毕 memset(rx_string,0x00,sizeof(rx_string)); //清空接收字符串 rx_cnt = 0; //清空计数器 } } HAL_UART_Receive_IT(&huart1, (uint8_t *)&rx_buff, 1); //再开启接收中断,若去掉只能接收一次 } }

完成!

附ascii码

在这里插入图片描述 在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3