你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【学习指南】基于STM32G474VET6 开发板实验经验分享(三)

[复制链接]
攻城狮Melo 发布时间:2024-11-22 18:11
第十、COMP 实验
实验目的:掌握和熟悉 G474 内部的模拟比较器用法,包括触发方式以及与内部 DAC 级联使用等。

1、软件读取 COMP 结果实验
CubeMX 配置如下,保存后生成对应的配置代码:
11.png

▲ CubeMX 进行 COMP 配置
本实验使用软件读取 COMP 比较结果,不需要配置触发,为了使比较结果更加直观,开启外部比较结果输出。


相关操作函数说明:
HAL_StatusTypeDef HAL_COMP_Start(COMP_HandleTypeDef *hcomp)
功能:开启比较器;
参数 1:比较器句柄,根据需要填写;
返回:操作结果,HAL_OK 或 HAL_ERROR;
示例:HAL_COMP_Start(&hcomp3);// 开启 COMP3HAL_StatusTypeDef HAL_COMP_Stop(COMP_HandleTypeDef *hcomp)
功能:关闭比较器;
参数 1:比较器句柄,根据需要填写;
返回:操作结果,HAL_OK 或 HAL_ERROR;
uint32_t HAL_COMP_GetOutputLevel(const COMP_HandleTypeDef *hcomp)
功能:读取比较器输出电平;
参数 1:比较器句柄,根据需要填写;
返回:比较结果,COMP_OUTPUT_LEVEL_LOW 或 COMP_OUTPUT_LEVEL_HIGH;
示例:result = HAL_COMP_GetOutputLevel(&hcomp3); //软件读取比较结果


核心代码:
if(HAL_COMP_Start(&hcomp3) != HAL_OK)
//开启比较器
{
Error_Handler();
}
while (1)
{
result = HAL_COMP_GetOutputLevel(&hcomp3); //软件读取比较结果
if(result == COMP_OUTPUT_LEVEL_HIGH)//比较结果为 1,即 INP 大于 INM
{
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_11);//翻转 LED2
}
HAL_Delay(100);
}


以上为 main 函数中外设初始化结束后的部分首先开启比较器,然后在主循环中每 100ms读取一次比较结果,如果结果为 1,即正相输入大于反相输入,则进行 LED2 翻转。


实验现象:
下载烧录后可以观察到拨动拨盘电位器,或者遮蔽光敏电阻时可以改变比较结果,CMP 亮时,LED2 状态不变,CMP 灭时,LED2 闪烁。

2、中断读取 COMP 结果实验
CubeMX 配置如下,保存后生成对应的配置代码:
2.png

▲ CubeMX 进行 COMP 配置


本实验使用中断读取 COMP 比较结果,在比较结果变化的上升沿和下降沿都触发中断,为了使比较结果更加直观,开启外部比较结果输出。


核心代码:
if(HAL_COMP_Start(&hcomp3) != HAL_OK)
//开启比较器
{
Error_Handler();
}


以上为 main 函数中外设初始化结束后的部分,这里只需要开启比较器即可,使用函数与上例相同。


void HAL_COMP_TriggerCallback(COMP_HandleTypeDef* hcomp)
{
if(hcomp->Instance==COMP3)
{
uint8_t temp;
temp = HAL_COMP_GetOutputLevel(&hcomp3);//读取比较结果
if(temp == COMP_OUTPUT_LEVEL_HIGH)//结果为 1,上升沿触发
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_10,GPIO_PIN_RESET);//点亮
LED1
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_11,GPIO_PIN_SET);//熄灭
LED2
}
else
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_10,GPIO_PIN_SET);//熄灭 LED1
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_11,GPIO_PIN_RESET);//点亮
LED2
}
}
}


以上为 COMP 触发中断回调函数,该回调函数为比较器共用,需要判断中断源,如果开启了多个边沿,还需要判断具体边沿。实质上,COMP 中断触发与 EXTI 类似,实际就是将COMP 比较输出作为一个 IO 映射到 EXTI 进行中断。


实验现象:
下载烧录后可以观察到拨动拨盘电位器,或者遮蔽光敏电阻时可以改变比较结果,CMP 亮时,LED1 灭,LED2 亮,CMP 灭时,LED1 亮,LED2 灭。


3、内部 DAC 级联比较实验
CubeMX 配置如下,保存后生成对应的配置代码:
3.png

▲ CubeMX 进行 COMP 配置
4.png

▲ CubeMX 进行 DAC 配置


本实验使用软件读取 COMP 比较结果,正相输入为光敏电阻,反相输入使用 DAC3 的 OUT1作为比较电压,为了使比较结果更加直观,开启外部比较结果输出。


核心代码:
void DAC3_CH1_Set_Vol(uint16_t vol)
{
double temp=vol;
temp/=1000;
temp=temp*4096/3.3;
HAL_DAC_SetValue(&hdac3,DAC_CHANNEL_1,DAC_ALIGN_12B_R,temp);//12 位右对齐数据格式设置 DAC 值
}


以上为 DAC 设置函数,通过该函数可以将输入的电压快速转换为 DAC 所需的寄存器数据。


DAC3_CH1_Set_Vol(500);//DAC 输出设置为 500mv
HAL_DAC_Start(&hdac3,DAC_CHANNEL_1);//生效 DAC 输出
if(HAL_COMP_Start(&hcomp3) != HAL_OK)
//开启比较器
{
Error_Handler();
}
while (1)
{
result = HAL_COMP_GetOutputLevel(&hcomp3); //软件读取比较结果
if(result == COMP_OUTPUT_LEVEL_HIGH)//比较结果为 1,即 INP 大于 INM
{
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_11);//翻转 LED2
}
HAL_Delay(100);
}
以上为 main 函数中外设初始化结束后的部分,首先设置好 DAC 输出电压,开启 DAC,然后开启比较器,最后在主循环中每 100ms 读取一次比较结果,如果结果为 1,即正相输入大于反相输入,则进行 LED2 翻转。


实验现象:
下载烧录后可以观察到遮蔽光敏电阻时可以改变比较结果,CMP 亮时,LED2 状态不变,CMP 灭时,LED2 闪烁。


第十一、FLASH 实验
实验目的:掌握和熟悉 G474 内部的 FLASH 用法,包括 FLASH 读写应用等。FLASH 读取无需进行配置。


核心代码:
/* 函数名:FLASH_Write
* 描述 :flash 写入数据
* 输入 :data 写入数据地址 addr flash 地址 size 写入字节数
* 输出 :无
* 调用 :FLASH_Write(data,FLASH_PAGE_127,8);//8 字节
*/
uint8_t FLASH_Write(uint8_t* data,uint32_t addr,uint16_t SIZE)
{
FLASH_EraseInitTypeDef EraseInitStruct;//定义擦写操作结构体
uint32_t SECTORError = 0;
uint64_t write_buff[10];//写入缓冲数组
uint8_t i = 0;
uint8_t size = SIZE/8;//8 字节写入次数
memcpy(write_buff,data,SIZE);//将输入的数组移动到写入缓冲区
HAL_FLASH_Unlock();//解锁
EraseInitStruct.Banks = FLASH_BANK_1; //存储区 1
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;//页擦除
EraseInitStruct.Page = (addr-0x08000000)/FLASH_PAGE_SIZE;//擦除页
EraseInitStruct.NbPages = 1;//擦除页数
if(HAL_FLASHEx_Erase(&EraseInitStruct,&SECTORError) != HAL_OK) //擦除页
{
return 1;//擦除失败
}
while(size)
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,addr,write_buff)!= HAL_OK)//双字写入
{
return 2;//写入失败
}
addr = addr+8;
i++;
size--;
}
HAL_FLASH_Lock(); //锁定 FLASH
return 0;
}
/* 函数名:FLASH_Read
* 描述 :flash 读取数据
* 输入 :data 读取数据地址 addr flash 地址 size 读取字节数
* 输出 :无
* 调用 :FLASH_Read(data,FLASH_PAGE_127,8);//8 字节
*/
uint8_t FLASH_Read(uint8_t* data,uint32_t addr,uint16_t SIZE)
{
uint32_t read_buff[10]; //接收缓冲数组
uint8_t i = 0;
uint16_t size = SIZE/4; //接收次数
while(size)
{
read_buff = *(__IO uint32_t*)addr; //从 FLASH 读取数据到接收缓冲数组
addr = addr+4;
i++;
size--;
}
memcpy(data,read_buff,SIZE); //将数据从接收缓冲数组转移到接收数组
return 0;
}


主要代码:
uint8_t data[8]={0,0,0,0,0,0,0,0};
char buf[30]="";
FLASH_Read(data,FLASH_PAGE_127,8);//8 字节
data[0]++;FLASH_Write(data,FLASH_PAGE_127,8);//8 字节
snprintf(buf,10,"times:%d",data[0]);
LCD_PutString(10,30,buf,Red,White,0);
uint32_t UID1=READ_REG(*((uint32_t *)UID_BASE));
uint32_t UID2=READ_REG(*((uint32_t *)(UID_BASE+4U)));
uint32_t UID3=READ_REG(*((uint32_t *)(UID_BASE+8U)));
snprintf(buf,30,"UID:%0x-%0x-%0x",UID1,UID2,UID3);
LCD_PutString(10,60,buf,Red,White,0);


实验现象:
下载烧录后可以观察到 LCD 显示 FLASH 测试次数以及芯片的 ID。
66.png

▲ 实验现象


第十二、单总线实验
实验目的:掌握和熟悉常用的单总线通信,包括 DS18B20,DHT11 读写应用。
CubeMX 配置如下,保存后生成对应的配置代码:
7.png

▲ 图 3.12.1 CubeMX 进行 GPIO 输出配置


本实验进行单总线读取 DS18B20 和 DHT11。使用 CUBEMX 配置 IO 为输出模式。


读取 DS18B20 核心代码:
/* 函数名:DS18B20_IO_OUT
* 功能:初始化 DS18B20 的 GPIO 为输出模式
* 输入:无
* 输出:无
* 备注:无
*/
void DS18B20_IO_OUT(void )
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
/* 函数名:DS18B20_IO_OUT
* 功能:初始化 DS18B20 的 GPIO 为输入模式
* 输入:无
* 输出:无
* 备注:无
*/void DS18B20_IO_IN(void )
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
/* 函数名:DS18B20_Rst
* 功能:复位 DS18B20
* 输入:无
* 输出:无
* 备注:无
*/
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //SET PG11 OUTPUT
DQ_OUT_LOW();
//拉低 DQ
delay_us(750);
//拉低 750us
DQ_OUT_HIGH();
//DQ=1
delay_us(15);
//15US
}
/* 函数名:DS18B20_Check
* 功能:等待 DS18B20 的回应
* 输入:无
* 输出:返回 1:未检测到 DS18B20 的存在 返回 0:存在
* 备注:无
*/
uint8_t DS18B20_Check(void)
{
uint8_t retry=0;
DS18B20_IO_IN();
//SET PG11 INPUT
while (DQ_GET_IN()&&retry<200)
{
retry++;delay_us(1);
};
if(retry>=200)return 1;
else retry=0;
while (!DQ_GET_IN()&&retry<240)
{
retry++;
delay_us(1);
};
if(retry>=240)return 1;
return 0;
}
/* 函数名:DS18B20_Read_Bit
* 功能:从 DS18B20 读取一个位
* 输入:无
* 输出:返回值:1/0
* 备注:无
*/
uint8_t DS18B20_Read_Bit(void)
{
uint8_t data;
DS18B20_IO_OUT(); //SET PG11 OUTPUT
DQ_OUT_LOW();delay_us(2);
DQ_OUT_HIGH();
DS18B20_IO_IN();
//SET PG11 INPUT
delay_us(12);
if(DQ_GET_IN())data=1;
else data=0;
delay_us(50);
return data;
}
/* 函数名:DS18B20_Read_Byte
* 功能:从 DS18B20 读取一个字节
* 输入:无
* 输出:返回值:读到的数据
* 备注:无
*/
uint8_t DS18B20_Read_Byte(void)
{
uint8_t i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
/* 函数名:DS18B20_Write_Byte
* 功能:写一个字节到 DS18B20
* 输入:dat:要写入的字节
* 输出:无
* 备注:无
*/
void DS18B20_Write_Byte(uint8_t dat)
{
uint8_t j;
uint8_t testb;
DS18B20_IO_OUT(); //SET PG11 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb)
{
DQ_OUT_LOW(); // Write 1
delay_us(2);
DQ_OUT_HIGH();
delay_us(60);
}
else
{
DQ_OUT_LOW(); // Write 0
delay_us(60);
DQ_OUT_HIGH();
delay_us(2);
}
}
}
/* 函数名:DS18B20_Start
* 功能:开始温度转换
* 输入:无
* 输出:无
* 备注:无
*/
//
void DS18B20_Start(void)
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0x44);// convert
}
/*
函数名:DS18B20_Start
* 功能:从 ds18b20 得到温度值 精度:0.1C
* 输入:无
* 输出:返回值:温度值 (-55.0~125.0)
* 备注:无
*/
short DS18B20_Get_Temp(void)
{
uint8_t temp;
uint8_t TL,TH;
short tem;DS18B20_Start ();
// ds1820 start convertDS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);// skip rom
DS18B20_Write_Byte(0xbe);// convert
TL=DS18B20_Read_Byte();
// LSB
TH=DS18B20_Read_Byte();
// MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;
//温度为负
}else temp=1;
//温度为正
tem=TH;
//获得高八位
tem<<=8;tem+=TL;
//获得底八位
tem=(float)tem*0.625;
//转换
char buf[20]="";
if(temp)snprintf(buf,10,"Temp:%.1f",tem/10.0);
else snprintf(buf,10,"Temp:%.1f",tem/10.0);
LCD_PutString(10, 10, buf, White,Blue,1);
if(temp)return tem;
//返回温度值
else return -tem;
}
读取 DHT11 核心代码:
/* 函数名:delay_us
* 功能:微秒延时
* 输入:delay 延时多少微秒
* 输出:无
* 备注:无
*/
#define CPU_FREQUENCY_MHZ 170
// STM32 时钟主频
void delay_us(__IO uint32_t delay)
{
int last, curr, val;
int temp;
while (delay != 0)
{
temp = delay > 900 ? 900 : delay;
last = SysTick->VAL;
curr = last - CPU_FREQUENCY_MHZ * temp;
if (curr >= 0)
{
do
{
val = SysTick->VAL;
}
while ((val < last) && (val >= curr));
}
else
{
curr += CPU_FREQUENCY_MHZ * 1000;
do
{
val = SysTick->VAL;
}
while ((val <= last) || (val > curr));
}
delay -= temp;
}
}
unsigned int rec_data[4];
/* 函数名:DH11_GPIO_Init_OUT
* 功能:初始化 DHT11 的 GPIO 为输出模式
* 输入:无
* 输出:无
* 备注:无
*/
void DH11_GPIO_Init_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}

// 对于 M0 来说,是输入
/* 函数名:DH11_GPIO_Init_IN
* 功能:初始化 DHT11 的 GPIO 为输入模式
* 输入:无
* 输出:无
* 备注:无
*/
void DH11_GPIO_Init_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
// DL_GPIO_initDigitalInput(GPIO_DQ_dht11_and_ds18b20_IOMUX);//配置为上拉输入
}
// 主机发送开始信号
/* 函数名:DHT11_Start
* 功能:主机发送开始信号
* 输入:无
* 输出:无
* 备注:无
*/
void DHT11_Start(void)
{
DH11_GPIO_Init_OUT(); // 输出模式
dht11_high; // 先拉高
delay_us(30);
dht11_low; // 拉低电平至少 18ms
HAL_Delay(20);
dht11_high; // 拉高电平 20~40us
DH11_GPIO_Init_IN(); // 输入模式
delay_us(30);
}
// 获取一个字节
/* 函数名:DHT11_Rec_Byte
* 功能:获取一个字节
* 输入:无
* 输出:读取的字符
* 备注:无
*/
char DHT11_Rec_Byte(void)
{
unsigned char i = 0;
unsigned char data;
for (i = 0; i < 8; i++) // 1 个数据就是 1 个字节 byte,1 个字节 byte 有 8 位 bit
{
while (dht11_read == 0)
;
// 从 1bit 开始,低电平变高电平,等待低电平结束
delay_us(30); // 延迟 30us 是为了区别数据 0 和数据 1,0 只有 26~28us
data <<= 1; // 左移
if (dht11_read == GPIO_PIN_SET) // 如果过了 30us 还是高电平的话就是数据 1
{
data |= 1; // 数据+1
}
while (dht11_read == GPIO_PIN_SET)
; // 高电平变低电平,等待高电平结束
}
return data;
}
// 获取数据
/* 函数名:DHT11_REC_Data
* 功能:获取 DHT11 数据并打印
* 输入:无
* 输出:无
* 备注:无
*/
void DHT11_REC_Data(void)
{
unsigned int R_H, R_L, T_H, T_L;
unsigned char RH, RL, TH, TL, CHECK;
DHT11_Start(); // 主机发送信号
//dht11_high; // 拉高电平
if (dht11_read == 0) // 判断 DHT11 是否响应
{
while (dht11_read == 0); // 低电平变高电平,等待低电平结束
while (dht11_read == GPIO_PIN_SET); // 高电平变低电平,等待高电平结束
R_H = DHT11_Rec_Byte();
R_L = DHT11_Rec_Byte();
T_H = DHT11_Rec_Byte();
T_L = DHT11_Rec_Byte();
CHECK = DHT11_Rec_Byte(); // 接收 5 个数据
//DH11_GPIO_Init_OUT();
//dht11_low; // 当最后一 bit 数据传送完毕后,DHT11 拉低总线 50us
delay_us(55); // 这里延时 55us
//dht11_high; // 随后总线由上拉电阻拉高进入空闲状态。
if (R_H + R_L + T_H + T_L == CHECK) // 和检验位对比,判断校验接收到的数据是否正确
{
RH = R_H;
RL = R_L;
TH = T_H;
TL = T_L;
}
}


rec_data[0] = RH;
rec_data[1] = RL;
rec_data[2] = TH;
rec_data[3] = TL;
char buf[20]="";
snprintf(buf,10,"Temp:%d.%d",TH,TL);
LCD_PutString(10, 10, buf, White,Blue,1);
snprintf(buf,10,"Hum:%d.%d",RH,RL);
LCD_PutString(10, 30, buf, White,Blue,1);}


主要代码:
while(1){
DHT11_REC_Data();//DHT11 读取
//DS18B20_Get_Temp();//18B20 读取
HAL_Delay(1000);
}


实验现象:
下载烧录后可以观察到 LCD 显示 DS18B20 测试的温度,或者 DHT11 测量的温度和湿度。
8.png

▲ 图 3.12.2 实验现象

第十三、独立看门狗
实验目的:掌握和熟悉独立看门狗用法,包括喂狗操作等。

CubeMX 配置如下,保存后生成对应的配置代码:
9.png
▲ 图 3.13.1 CubeMX 进行独立看门狗配置

本实验进行独立看门狗配置。使用 CUBEMX 配置 IO 为输出输入模式实现 LED 指示和按键读取,GPIO 配置参考上文。程序中使用按键喂狗,如果没在 1s 内喂狗,系统将会自动复位。

主要代码:
while (1)
{
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)==0)
{
HAL_Delay(5);
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)==0)
{
HAL_IWDG_Refresh(&hiwdg);
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_10);
while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4));
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}


实验现象:
下载烧录后可以观察到如果在一定时间内进行喂狗操作,系统会复位,LCD 重新加载。
10.png
▲ 图 3.13.2 实验现象


转载自: AI电堂
如有侵权请联系删除




55.png
收藏 评论0 发布时间:2024-11-22 18:11

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版