发新帖本帖赏金 50.00元(功能说明)我要提问
返回列表
打印
[AT32M412]

【AT-START-M412测评】+ ④夏季室内温控系统

[复制链接]
630|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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开发板评测活动]内容优质

发新帖 本帖赏金 50.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

106

主题

1095

帖子

7

粉丝