IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【各种中断】STM32cubeMX HAL库综合复习 -> 正文阅读

[嵌入式]【各种中断】STM32cubeMX HAL库综合复习

小蜜蜂老师32cubemx学习笔记,对一些实验过程中可能出现的情况做出解释,对老师做补充,重复性工作ctrl+c/v使用,前期略显粗糙,后续随时更新,有错误感谢指正,根据自己板子的情况对视频中的程序做了调整,比如实在懒得加第二个LED灯~还有手头没有光敏,但有一个土壤湿度~很多地方写了注释,说不定你不明白的地方就写在注释里面~


在这里插入图片描述

这个是参考视频的链接,感谢这位UP我才能学的这么快😄点击即可:小蜜蜂老师B站课程链接
在这里插入图片描述
编译一下就有那个打开折叠的加号了~

有IT就对应中断,就要设置NVIC使能,就有回调函数,满足对应条件就会触发回调函数,中断的思维很重要~
要注意你的板载LED灯是不是低电平才亮,接的单片机的哪个引脚捏~
不得不说这软件真的好好用啊~
回调函数里不要用HAL_Delay()

一、外部中断

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM2)
	{
	
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
		
	}
	if(htim->Instance==TIM3)
	{
	
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
		
	}

}
//定时器中断回调函数与中断判断,对应定时器中断会触发电平反转

初始化部分:

HAL_TIM_Base_Start_IT(&htim2);//定时器启动函数

原型:

HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);

二、串口

有的串口助手没有显示文本功能,所以没办法显示中文(中文是乱码,改成同义的英文即可)。
定义与宏:

uint8_t Tx_str1[]="Hello,world!\r\n";
uint8_t Tx_str2[]="LED1_Open!\r\n";
uint8_t Tx_str3[]="LED1_Close!\r\n";
//字符串声明

#define LED1_ON() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);//宏定义的方法,不仅可以定义返回值,还可以定义函数

串口接收中断回调函数:

//回调函数的用法

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{

	if(huart->Instance==USART2)//传递过来的实例是usart2的话
	{
	
		if(Rx_dat==0xa1)
		{
			LED1_ON();
			
			LED2_OFF();
			
			HAL_UART_Transmit(&huart2,Tx_str1,sizeof(Tx_str1),10000);
		
			LED2_OFF();
			
			HAL_UART_Receive_IT(&huart2,&Rx_dat,1);//记得重新打开,写到内层的if里就行,继续接收中断请求,写到while(1)里面也可以
		}	
			
		else if(Rx_dat==0xa2)
		{
			LED1_OFF();
			
			LED2_ON();
			
			HAL_UART_Transmit(&huart2,Tx_str1,sizeof(Tx_str1),10000);
		
			LED2_OFF();
			
			HAL_UART_Receive_IT(&huart2,&Rx_dat,1);
		}
	}
}

初始化部分:

HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);

HAL_UART_Transmit(&huart2,Tx_str1,sizeof(Tx_str1),10000);          //非阻塞式输出,启动提示,最后一位是超时重置

HAL_UART_Receive_IT(&huart2,&Rx_dat,1);      //初始化的时候需要写一下,开启接收

//接收和传输

三、定时器串口混合应用

在cubemx里面把预分频器与主计数器设置好数值~
手动引入新的头文件、定义与宏,位置:BEGIN0:

#include "stdio.h"//手动加入在USER CODE BEGIN Includes 中
#define LED_on() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET)//这个位置不带分号,后边调用该宏就要加上分号,如果这个位置加分号,后面调用时再加分号相当于有两个分号
#define LED_off() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET)
#define LED_invert() HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13)

uint8_t str1[]="==============Hello!================\r\n";
uint8_t hh=0,mm=0,ss=0,ss05=0;
uint8_t str_buff[64];//64个字节
uint8_t Rx_dat[16];//16个字节
		
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
	
		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
		
		ss05++;
		if(ss05==2)
		{
		
			ss05=0;
			ss++;
			if(ss==60)
			{
				ss=0;
				mm++;
				if(mm==60)
				{
					mm=0;
					hh++;
				}
			}
		}
	}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{

	if(huart->Instance==USART2)//传递过来的实例是usart2的话
	{
		if(Rx_dat[0]==0xBF&&Rx_dat[2]==0xFB)//帧头和帧尾
		{
			switch(Rx_dat[1])
			{
				case 0xa1:
				sprintf((char *)str_buff,"%d:%d:%d   LED open!\r\n",hh,mm,ss);//标准化输出
				break;
				
				case 0xa2:
				sprintf((char *)str_buff,"%d:%d:%d   LED close!\r\n",hh,mm,ss);
				break;

				default://都不是的话
				sprintf((char *)str_buff,"%d:%d:%d   This is an error!\r\n",hh,mm,ss);
				break;
			}
			HAL_UART_Transmit(&huart2,str_buff,sizeof(str_buff),10000);
			HAL_UART_Receive_IT(&huart2,Rx_dat,3); 
		}	
	}
}

if(ss05==2),当时设置的是500ms中断一次,所以中断两次秒才能加一
初始化,位置:BEGIN2:

	HAL_UART_Transmit(&huart2,str1,sizeof(str1),10000);
	HAL_TIM_Base_Start_IT(&htim2);//定时器启动函数
	HAL_UART_Receive_IT(&huart2,Rx_dat,3);  
	
	//HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
	
	//HAL_UART_Transmit(&huart2,Tx_str1,sizeof(Tx_str1),10000);
	
	//HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
		
	//HAL_UART_Receive_IT(&huart2,&Rx_dat,1);

感觉在循环中写电平翻转有点问题??

四、数模转换

若是查询式

#include "stdio.h"
#define LED1_ON() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET)
uint8_t str1[]="==============Hello!================\r\n";
uint16_t ADC_Val = 0,ADC_Volt=0;

uint8_t str_buff[44];

void UART1_Send_Info()
{
	sprintf((char *)str_buff,"Sample_Val:%d,Volt_Val:%d.%d%dV\r\n",ADC_Val,ADC_Volt/100,(ADC_Volt%100)/10,ADC_Volt%10);
	HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000);
}//用到哪个函数就要在用到的位置之前就已经写好,或者在之后再写但前面提前做好声明

void ADC0_Get_Val()
{
	HAL_ADC_Start(&hadc1);//用ADC的实例地址启动
	LED1_ON();
	if(HAL_ADC_PollForConversion(&hadc1,10) == HAL_OK)//10是超时时间
	{
		ADC_Val = HAL_ADC_GetValue(&hadc1);
		ADC_Volt = ADC_Val*330/4096;	
	}	
	UART1_Send_Info();
	LED1_OFF();
	HAL_ADC_Stop(&hadc1);
}
————————————————初始化——————————————————————	
	HAL_UART_Transmit(&huart1,str1,sizeof(str1),10000);
————————————————主循环——————————————————————
ADC0_Get_Val();
		HAL_Delay(500);

若是中断式

#include "stdio.h"
#define LED1_ON() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET)
uint8_t str1[]="==============Are you ok?================\r\n";
uint16_t ADC_Val = 0,ADC_Volt=0;

uint8_t str_buff[44];

void UART1_Send_Info()
{
	sprintf((char *)str_buff,"Sample_Val:%d,Volt_Val:%d.%d%dV\r\n",ADC_Val,ADC_Volt/100,(ADC_Volt%100)/10,ADC_Volt%10);
	HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000);
}//用到哪个函数就要在用到的位置之前就已经写好,或者在之后再写但前面提前做好声明

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc->Instance == ADC1)
	{
		ADC_Val = HAL_ADC_GetValue(&hadc1);
		ADC_Volt = ADC_Val*330/4096;	
		UART1_Send_Info();
		LED1_OFF();
	}
}

————————————————————————————begin2——————————————————————————
	HAL_UART_Transmit(&huart1,str1,sizeof(str1),10000);
————————————————————————————主循环————————————————————————————
	LED1_ON();
	HAL_ADC_Start_IT(&hadc1);
	HAL_Delay(500);

ADC_Volt = ADC_Val*330/4096;
这句话里的4096是212得来的,12位的AD嘛不是,330是3.3V乘100得来的,3.3是参考电压,也是我们插上STlinkV2给板子的输入电压,为什么乘100呢?因为在下面这个句子里,为了让输出的电压单位为V,就不得不用小数去表示电压,为了不让测得的电压显示时损失太多精度,先乘了100后边又除以了一个100,保证了两位小数的电压实际值输出。
sprintf((char *)str_buff,“Sample_Val:%d,Volt_Val:%d.%d%dV\r\n”,ADC_Val,ADC_Volt/100,(ADC_Volt%100)/10,ADC_Volt%10);
好像说的不是很明白。。。。后续再说

五、OLED(SPI)

四脚的是IIC的,七脚的是SPI的,两者差别很大,视频用的后者~
小蜜蜂老师整理的OLED资料与函数讲解
注意:RES脚要接到开发板的RESET脚上(每个板子应该都有的,引出来现成的),这样当你按下32的手动reset按钮时,也会给OLED屏幕复位,这个脚接不好屏幕直接不工作,不是连一个按钮接地这么简单(当时找错误找了好久好久)。

/* USER CODE BEGIN Includes */
#include "XMF_OLED_STM32Cube.h"
/* USER CODE END Includes */

/* USER CODE BEGIN 0 */
extern unsigned char BMP1[];

void OLED_display_pic()
{
	OLED_Clear();
	OLED_DrawBMP(0,0,128,7,BMP1);
}


void OLED_display_info()
{
	OLED_Clear();
	//OLED_ShowString(16,0,(uint8_t *)"Hello,world!");//十六个像素是一行字,8个像素是一页,也就是一行字要两页,老师好像是这个意思
	//OLED_ShowChinese(16,2,(uint8_t *)"Hello,world!");//占掉第34页
	//OLED_ShowString(16,4,(uint8_t *)"Hello,world!");//占掉第56页
	//OLED_ShowString(16,6,(uint8_t *)"2022/01/28");//占掉第78页,一列一共64个像素,一共8页,对应编号0—7
	OLED_ShowString(16,0,(uint8_t *)"Hello,World!");
	OLED_ShowCHinese(10,3,0);
	OLED_ShowCHinese(28,3,1);
	OLED_ShowCHinese(46,3,2);
	OLED_ShowCHinese(64,3,3);
	OLED_ShowCHinese(82,3,4);
	
}

/* USER CODE END 0 */

/* USER CODE BEGIN 2 */
	OLED_Init();
	OLED_display_pic();
	HAL_Delay(500);
	OLED_display_info();
/* USER CODE END 2 */

OLED_Init();别忘了初始化
OLED_ShowCHinese(82,3,4);最后一位4是指汉字库(HZK)里的第四个字~
看好了他拼的有点奇怪,不是Chinese而是CHinese~

六、OLED+AD

/* USER CODE BEGIN 0 */
#include "stdio.h"

#define LED_ON() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET)
#define LED_OFF() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET)
extern unsigned char BMP1[];
uint16_t ADC_val=0,ADC_volt=0;
uint8_t str_buff[64];
void led_check()
{
	LED_ON();
	HAL_Delay(300);
	LED_OFF();
	HAL_Delay(300);
}


void oled_display_pic()
{
	OLED_Clear();
	OLED_DrawBMP(0,0,128,8,BMP1);
}
void oled_display_info()
{
	OLED_Clear();//不清屏就会和前一个图像同时输出在一个屏幕上
	OLED_ShowString(0,0,(uint8_t *)"Blog of Z_0_0");//强制类型转换?
	OLED_ShowCHinese(0,3,3);
	OLED_ShowCHinese(18,3,4);
	OLED_ShowCHinese(36,3,8);
	OLED_ShowString(54,3,(uint8_t *)":");
	
	OLED_ShowCHinese(0,5,0);
	OLED_ShowCHinese(18,5,1);
	OLED_ShowCHinese(36,5,8);
	OLED_ShowString(54,5,(uint8_t *)":");
	OLED_ShowString(100,5,(uint8_t *)"V");
	
	
}

void oled_display_data()
{
	sprintf((char *)str_buff,"%d",ADC_val);
	OLED_ShowString(64,3,str_buff);
	sprintf((char *)str_buff,"%d.%d%d",ADC_volt/100,(ADC_volt%100)/10,ADC_volt%10);//把文字与变化的数值结合,下一步再输出
	OLED_ShowString(64,5,str_buff);//sprintf可以把数字字母都塞到str_buff里面
	
}

void GET_adc_val()
{
	HAL_ADC_Start(&hadc1);
	if(HAL_ADC_PollForConversion(&hadc1,10)== HAL_OK)
	{
		ADC_val=HAL_ADC_GetValue(&hadc1);
		ADC_volt=ADC_val*330/4096;
		oled_display_data();
	}
	if(ADC_volt<200)
	{
		LED_ON();
	}
	else
	{
		LED_OFF();
	}
}

/* USER CODE END 0 */

  /* USER CODE BEGIN 2 */	
	OLED_Init();
	oled_display_pic();
	oled_display_info();
  /* USER CODE END 2 */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		
		GET_adc_val();
		HAL_Delay(300);
    /* USER CODE END WHILE */

土壤湿度传感器与沾水的卫生纸配合使用~
在这里插入图片描述
电压值最大是3.3V肯定
在这里插入图片描述
把土壤湿度传感器摁在湿润的卫生纸上~
在这里插入图片描述

使用%d输出时,上一次采样到的模拟值有四位数字这次采样是三位的话,如上一次3978,这次采样得到465,屏幕上会显示4658,这个多出来的8是由于上次3978第四位的8还留在屏幕上没有刷新掉,换成%4d三位数字实际上是465加一个空格,这样把上一次采样第四位8给挤掉了,显示就正常了。

实际上就是显示的问题,数字采样没错误,不用屏幕输出的情况完全不用考虑这个BUG。
测试%d与%4d的区别,%d是按照原型输出,有多少位就有多少位,另外c语言中数据的宽度是从右边开始算起的,比如%4d就表示数据宽度为4,不够的那空格来补,如果超出四位,则应该原型输出。具体测试程序如下,只需粘贴复制到VC6.0上运行就可知道两者的区别。
该段出自:%4d与%d讲解

本文后续再更新~感谢大家支持!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-01-30 19:05:27  更:2022-01-30 19:07:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:15:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码