本帖最后由 yinwuqing110 于 2025-6-22 19:30 编辑
一、引言
前面帖子也分享了正常驱动DS18B20模块,今天分享一下,在上期工程的基础上,增加驱动电机模块,实现一个简易的夏季降温控制装置。夏季到来,南方室内温度过高,很难入睡。一整晚开着空调觉得太费电,整夜开着吊扇又怕着凉感冒,那如果使用一套自动控温装置,既能实现节能减排,又能达到精准降温,非常适用。
二、电机驱动模块
原本使用42步进电机驱动器去驱动42步进电机,结果没有相应的风扇叶,驱动演示效果不怎么理想。然后选择采用L298N电机驱动模块,连接12V直流电机,并拧紧风扇叶片,驱动效果非常不错。
下面介绍一下L298N模块的基本资料。
由上图可知,该驱动板可驱动两路直流电机,使能端ENA,ENB为高电平有效,控制方式及直流电机状态表如下所示:
若要对直流电机进行PWM调速控制,则需要设置IN1和IN2,确定电机的转动方向,然后对使能端输出PWM脉冲,即可实现调速。注意当使能信号为0时,电机处于自动停止状态;当使能信号为1,且IN1和IN2为00或11时,电机处于制动状态,阻止电机转动。
三、硬件接口
根据《DS_AT32M412_416_V2.01_ZH.pdf》数据手册,结合《AT_START_M412_V1.0_SCH.pdf》原理图,管脚复用关系,选择相应IO口。为了更好的交互体验,这里还引入蜂鸣报警器模块,占用一个GPIO口。综上情况,实验中使用到的硬件接口关系列表如下:
因为电机是12V直流电机,因此L298N模块采用12V供电。结合板上的VCC与GND管脚分布,硬件实物连接图见如下:
四、驱动源码
原本使用GPIO中断方式触发电机启动,然而LCD屏显示温度变的没那么流畅,因此直接采用循环检测模式,体验效果还不错。之前也分享了LCD、DS18B20的驱动源码,今儿就不再分享这部分代码,有需要的网友请翻阅前期发布的帖子。
L298N与Beep初始化驱动部分代码如下:
motor.h
#ifndef __MOTOR_H
#define __MOTOR_H
#include "at32m412_416_board.h"
#include "at32m412_416_clock.h"
void motor_crm_configuration(void);
void motor_gpio_configuration(void);
void beep_gpio_configuration(void);
#endif /* __MOTOR_H */
motor.c
#include "motor.h"
#include <stdio.h>
void motor_crm_configuration(void)
{
/* tmr3 clock enable */
crm_periph_clock_enable(CRM_TMR3_PERIPH_CLOCK, TRUE);
/* gpioa gpiob clock enable */
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
}
void motor_gpio_configuration(void)
{
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_pins = GPIO_PINS_1;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOB, &gpio_init_struct);
gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE1, GPIO_MUX_2);
gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_10;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOB, &gpio_init_struct);
}
void beep_gpio_configuration(void)
{
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_pins = GPIO_PINS_5;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOB, &gpio_init_struct);
gpio_bits_reset(GPIOB,GPIO_PINS_5);
}
main.c
#include "at32m412_416_board.h"
#include "at32m412_416_clock.h"
#include <math.h>
#include "lcd_st7735.h"
#include "DS18B20.h"
#include "motor.h"
#define TEMP_THRESHOLD 31.8
tmr_output_config_type tmr_oc_init_structure;
crm_clocks_freq_type crm_clocks_freq_struct = {0};
volatile float temperature = 0;
uint16_t ccr1_val = 333;
uint16_t ccr2_val = 444;
uint16_t ccr3_val = 555;
uint16_t ccr4_val = 666;
uint16_t prescalervalue = 0;
int main(void)
{
uint8_t i, DS18B20ID[8];
char str[50];
system_clock_config();
at32_board_init();
motor_crm_configuration();
crm_clocks_freq_get(&crm_clocks_freq_struct);
motor_gpio_configuration();
beep_gpio_configuration();
uart_print_init(115200);
/* compute the prescaler value */
prescalervalue = (uint16_t) ((crm_clocks_freq_struct.apb1_freq) / 24000000) - 1;
/* tmr3 time base configuration */
tmr_base_init(TMR3, 665, prescalervalue);
tmr_cnt_dir_set(TMR3, TMR_COUNT_UP);
tmr_clock_source_div_set(TMR3, TMR_CLOCK_DIV1);
tmr_output_default_para_init(&tmr_oc_init_structure);
tmr_oc_init_structure.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
tmr_oc_init_structure.oc_idle_state = FALSE;
tmr_oc_init_structure.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
tmr_oc_init_structure.oc_output_state = TRUE;
tmr_output_channel_config(TMR3, TMR_SELECT_CHANNEL_4, &tmr_oc_init_structure);
tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr1_val);
tmr_output_channel_buffer_enable(TMR3, TMR_SELECT_CHANNEL_4, TRUE);
tmr_period_buffer_enable(TMR3, TRUE);
/* tmr enable counter */
tmr_counter_enable(TMR3, TRUE);
tmr_output_enable(TMR3, TRUE);
LcdInit();
printf("DS18B20温度传感器信息读取\n");
LcdFill(0,0,128,160,BLACK);
LcdShowString(2,24,"DS18B20",RED, BLACK,16);
LcdShow16x16Hz(60, 24, 10, YELLOW, BLACK);
LcdShow16x16Hz(76, 24, 11, YELLOW, BLACK);
LcdShow16x16Hz(92, 24, 12, YELLOW, BLACK);
LcdShow16x16Hz(108, 24, 13, YELLOW, BLACK);
LcdShow16x16Hz(2, 48, 14, YELLOW, BLACK);
LcdShow16x16Hz(18, 48, 15, YELLOW, BLACK);
LcdShow16x16Hz(34, 48, 16, YELLOW, BLACK);
LcdShow16x16Hz(50, 48, 17, YELLOW, BLACK);
LcdShow16x16Hz(66, 48, 18, YELLOW, BLACK);
delay_ms(2000);
while(DS18B20_Init())
{
printf("DS18B20温度传感器不存在\n");
LcdFill(0,0,128,160,BLACK);
LcdShowString(2,24,"DS18B20",RED, BLACK,16);
LcdShow16x16Hz(60, 24, 10, YELLOW, BLACK);
LcdShow16x16Hz(76, 24, 11, YELLOW, BLACK);
LcdShow16x16Hz(92, 24, 12, YELLOW, BLACK);
LcdShow16x16Hz(108, 24, 13, YELLOW, BLACK);
LcdShow16x16Hz(2, 48, 14, YELLOW, BLACK);
LcdShow16x16Hz(18, 48, 19, YELLOW, BLACK);
LcdShow16x16Hz(34, 48, 20, YELLOW, BLACK);
LcdShow16x16Hz(50, 48, 21, YELLOW, BLACK);
delay_ms(1000);
}
printf("检测到DS18B20温度传感器,并初始化成功\n");
LcdFill(0,0,128,160,BLACK);
LcdShow16x16Hz(2, 24, 22, YELLOW, BLACK);
LcdShow16x16Hz(18, 24, 23, YELLOW, BLACK);
LcdShow16x16Hz(34, 24, 24, YELLOW, BLACK);
LcdShowString(50,24,"DS18B20",RED, BLACK,16);
LcdShow16x16Hz(108, 24, 10, YELLOW, BLACK);
LcdShow16x16Hz(2, 48, 11, YELLOW, BLACK);
LcdShow16x16Hz(18, 48, 12, YELLOW, BLACK);
LcdShow16x16Hz(34, 48, 13, YELLOW, BLACK);
LcdShow16x16Hz(50, 48, 14, YELLOW, BLACK);
LcdShowString(66,48,",",YELLOW, BLACK,16);
LcdShow16x16Hz(74, 48, 25, YELLOW, BLACK);
LcdShow16x16Hz(90, 48, 26, YELLOW, BLACK);
LcdShow16x16Hz(106, 48, 27, YELLOW, BLACK);
LcdShow16x16Hz(2, 72, 28, YELLOW, BLACK);
LcdShow16x16Hz(18, 72, 29, YELLOW, BLACK);
LcdShow16x16Hz(34, 72, 30, YELLOW, BLACK);
DS18B20_ReadId(DS18B20ID);
printf("DS18B20的序列号是: 0x");
for ( i = 0; i < 8; i ++ )
printf ( "%.2X", DS18B20ID[i]);
printf("\n");
sprintf(str,"0x%02X%02X%02X%02X%02X%02X%02X%02X",DS18B20ID[0],DS18B20ID[1],DS18B20ID[2],DS18B20ID[3],
DS18B20ID[4],DS18B20ID[5],DS18B20ID[6],DS18B20ID[7]);
LcdShowString(8,96,"DS18B20",RED, BLACK,12);
LcdShow16x16Hz(50, 96, 32, YELLOW, BLACK);
LcdShow16x16Hz(66, 96, 33, YELLOW, BLACK);
LcdShow16x16Hz(82, 96, 34, YELLOW, BLACK);
LcdShow16x16Hz(98, 96, 35, YELLOW, BLACK);
LcdShow16x16Hz(114, 96, 40, YELLOW, BLACK);
LcdShowString(8,120,str,RED,BLACK,12);
delay_ms(2000);
while(1)
{
temperature = DS18B20_GetTemp_MatchRom(DS18B20ID);
/* 打印通过 DS18B20 序列号获取的温度值 */
printf("获取该序列号器件的温度:%.1f\n",temperature);
LcdFill(0,0,128,160,BLACK);
LcdShow16x16Hz(2, 8, 36, YELLOW, BLACK);
LcdShow16x16Hz(18, 8, 37, YELLOW, BLACK);
LcdShow16x16Hz(34, 8, 10, YELLOW, BLACK);
LcdShow16x16Hz(50, 8, 11, YELLOW, BLACK);
LcdShow16x16Hz(66, 8, 38, YELLOW, BLACK);
LcdShow16x16Hz(82, 8, 39, YELLOW, BLACK);
LcdShow16x16Hz(98, 8, 40, YELLOW, BLACK);
LCD_ShowFloatNum1(8,32,temperature,4,RED, BLACK,24);
LcdShow16x16Hz(70, 36, 41, RED, BLACK);
delay_ms(200);
if(temperature <= TEMP_THRESHOLD) {
tmr_output_enable(TMR3, FALSE);
gpio_bits_reset(GPIOB,GPIO_PINS_5);
gpio_bits_reset(GPIOB,GPIO_PINS_2);
gpio_bits_reset(GPIOB,GPIO_PINS_10);
}else if (temperature-TEMP_THRESHOLD <= 0.5) {
// 启动风机逆时针旋转
gpio_bits_reset(GPIOB,GPIO_PINS_10);
gpio_bits_set(GPIOB,GPIO_PINS_2);
tmr_output_enable(TMR3, FALSE);
tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr1_val);
tmr_output_enable(TMR3, TRUE);
gpio_bits_toggle(GPIOB,GPIO_PINS_5);
delay_ms(500);
}else if(temperature-TEMP_THRESHOLD <= 1.5) {
tmr_output_enable(TMR3, FALSE);
tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr2_val);
tmr_output_enable(TMR3, TRUE);
gpio_bits_toggle(GPIOB,GPIO_PINS_5);
delay_ms(200);
}else if(temperature-TEMP_THRESHOLD <= 2.5) {
tmr_output_enable(TMR3, FALSE);
tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr3_val);
tmr_output_enable(TMR3, TRUE);
gpio_bits_toggle(GPIOB,GPIO_PINS_5);
delay_ms(50);
}else if(temperature-TEMP_THRESHOLD <= 3.5) {
tmr_output_enable(TMR3, FALSE);
tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr4_val);
tmr_output_enable(TMR3, TRUE);
gpio_bits_toggle(GPIOB,GPIO_PINS_5);
delay_ms(10);
}
else {
tmr_output_enable(TMR3, FALSE);
gpio_bits_reset(GPIOB,GPIO_PINS_5);
gpio_bits_reset(GPIOB,GPIO_PINS_2);
gpio_bits_reset(GPIOB,GPIO_PINS_10);
}
}
}
根据以上代码可知,温度门限控制在31.8℃以下,高于该温度0.5℃内为一等级预警;高于1.5℃为二等级报警;高于2.5℃为三等级鸣警;高于3.5℃为四等级超温告警。每等级驱动的PWM占空比不同,因此驱动电机的转速也不同,蜂鸣器告警的频率也不同。
五、效果演示
使用手指触摸DS18B20给温度传感器加温,当温度超过限定阀值时,则启动风机,并唤起蜂鸣器报警提示,吹风给DS18B20模块降温;当温度还持续加热,则启动更高等级的风速与报警频率,等级越高,风速越快越大,因此降温越快。风吹着降温明显,正如演示视频当中,用手指加温的同时,风机启动了加温进度明显减慢了。
视频演示见B站:https://www.bilibili.com/video/BV1kHNRzsEDh/
|
打赏榜单
ArteryMCU 打赏了 50.00 元 2025-07-04 理由:[M412开发板评测活动]内容优质
|