返回列表 发新帖我要提问本帖赏金: 50.00元(功能说明)

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

[复制链接]
 楼主| yinwuqing110 发表于 2025-6-22 19:10 | 显示全部楼层 |阅读模式
本帖最后由 yinwuqing110 于 2025-6-22 19:30 编辑

一、引言        
          前面帖子也分享了正常驱动DS18B20模块,今天分享一下,在上期工程的基础上,增加驱动电机模块,实现一个简易的夏季降温控制装置。夏季到来,南方室内温度过高,很难入睡。一整晚开着空调觉得太费电,整夜开着吊扇又怕着凉感冒,那如果使用一套自动控温装置,既能实现节能减排,又能达到精准降温,非常适用。
二、电机驱动模块
      原本使用42步进电机驱动器去驱动42步进电机,结果没有相应的风扇叶,驱动演示效果不怎么理想。然后选择采用L298N电机驱动模块,连接12V直流电机,并拧紧风扇叶片,驱动效果非常不错。
      下面介绍一下L298N模块的基本资料。
L298N模块.png
      由上图可知,该驱动板可驱动两路直流电机,使能端ENA,ENB为高电平有效,控制方式及直流电机状态表如下所示:
逻辑关系.png
       若要对直流电机进行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口。综上情况,实验中使用到的硬件接口关系列表如下:
管脚使用列表.png
     因为电机是12V直流电机,因此L298N模块采用12V供电。结合板上的VCC与GND管脚分布,硬件实物连接图见如下:
硬件实物连接图.jpg
四、驱动源码
     原本使用GPIO中断方式触发电机启动,然而LCD屏显示温度变的没那么流畅,因此直接采用循环检测模式,体验效果还不错。之前也分享了LCD、DS18B20的驱动源码,今儿就不再分享这部分代码,有需要的网友请翻阅前期发布的帖子。
L298N与Beep初始化驱动部分代码如下:
motor.h
  1. #ifndef __MOTOR_H
  2. #define __MOTOR_H

  3. #include "at32m412_416_board.h"
  4. #include "at32m412_416_clock.h"

  5. void motor_crm_configuration(void);
  6. void motor_gpio_configuration(void);
  7. void beep_gpio_configuration(void);

  8. #endif        /* __MOTOR_H */
motor.c
  1. #include "motor.h"
  2. #include <stdio.h>

  3. void motor_crm_configuration(void)
  4. {
  5.   /* tmr3 clock enable */
  6.   crm_periph_clock_enable(CRM_TMR3_PERIPH_CLOCK, TRUE);

  7.   /* gpioa gpiob clock enable */
  8.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  9.   crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
  10. }

  11. void motor_gpio_configuration(void)
  12. {
  13.   gpio_init_type gpio_init_struct;

  14.   gpio_default_para_init(&gpio_init_struct);

  15.   gpio_init_struct.gpio_pins =  GPIO_PINS_1;
  16.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  17.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  18.   gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  19.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;

  20.   gpio_init(GPIOB, &gpio_init_struct);
  21.   gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE1, GPIO_MUX_2);
  22.         
  23.   gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_10;
  24.   gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  25.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  26.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  27.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  28.   gpio_init(GPIOB, &gpio_init_struct);
  29. }

  30. void beep_gpio_configuration(void)
  31. {
  32.   gpio_init_type gpio_init_struct;

  33.   gpio_default_para_init(&gpio_init_struct);

  34.   gpio_init_struct.gpio_pins = GPIO_PINS_5;
  35.   gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  36.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  37.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  38.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  39.   gpio_init(GPIOB, &gpio_init_struct);
  40.   gpio_bits_reset(GPIOB,GPIO_PINS_5);
  41. }
main.c
  1. #include "at32m412_416_board.h"
  2. #include "at32m412_416_clock.h"
  3. #include <math.h>
  4. #include "lcd_st7735.h"
  5. #include "DS18B20.h"
  6. #include "motor.h"

  7. #define TEMP_THRESHOLD 31.8

  8. tmr_output_config_type tmr_oc_init_structure;
  9. crm_clocks_freq_type crm_clocks_freq_struct = {0};

  10. volatile float temperature = 0;
  11. uint16_t ccr1_val = 333;
  12. uint16_t ccr2_val = 444;
  13. uint16_t ccr3_val = 555;
  14. uint16_t ccr4_val = 666;
  15. uint16_t prescalervalue = 0;

  16. int main(void)
  17. {
  18.    uint8_t i, DS18B20ID[8];
  19.    char str[50];
  20.         
  21.   system_clock_config();
  22.   at32_board_init();
  23.   motor_crm_configuration();
  24.   crm_clocks_freq_get(&crm_clocks_freq_struct);
  25.   motor_gpio_configuration();
  26.   beep_gpio_configuration();
  27.   uart_print_init(115200);
  28.         
  29. /* compute the prescaler value */
  30.   prescalervalue = (uint16_t) ((crm_clocks_freq_struct.apb1_freq) / 24000000) - 1;

  31.   /* tmr3 time base configuration */
  32.   tmr_base_init(TMR3, 665, prescalervalue);
  33.   tmr_cnt_dir_set(TMR3, TMR_COUNT_UP);
  34.   tmr_clock_source_div_set(TMR3, TMR_CLOCK_DIV1);

  35.   tmr_output_default_para_init(&tmr_oc_init_structure);
  36.   tmr_oc_init_structure.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
  37.   tmr_oc_init_structure.oc_idle_state = FALSE;
  38.   tmr_oc_init_structure.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
  39.   tmr_oc_init_structure.oc_output_state = TRUE;

  40.   tmr_output_channel_config(TMR3, TMR_SELECT_CHANNEL_4, &tmr_oc_init_structure);
  41.   tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr1_val);
  42.   tmr_output_channel_buffer_enable(TMR3, TMR_SELECT_CHANNEL_4, TRUE);
  43.   tmr_period_buffer_enable(TMR3, TRUE);

  44.   /* tmr enable counter */
  45.   tmr_counter_enable(TMR3, TRUE);
  46.   tmr_output_enable(TMR3, TRUE);
  47.         
  48.   LcdInit();
  49.   printf("DS18B20温度传感器信息读取\n");
  50.   LcdFill(0,0,128,160,BLACK);
  51.   LcdShowString(2,24,"DS18B20",RED, BLACK,16);
  52.   LcdShow16x16Hz(60, 24, 10, YELLOW, BLACK);
  53.   LcdShow16x16Hz(76, 24, 11, YELLOW, BLACK);
  54.   LcdShow16x16Hz(92, 24, 12, YELLOW, BLACK);
  55.   LcdShow16x16Hz(108, 24, 13, YELLOW, BLACK);
  56.   LcdShow16x16Hz(2, 48, 14, YELLOW, BLACK);
  57.   LcdShow16x16Hz(18, 48, 15, YELLOW, BLACK);
  58.   LcdShow16x16Hz(34, 48, 16, YELLOW, BLACK);
  59.   LcdShow16x16Hz(50, 48, 17, YELLOW, BLACK);
  60.   LcdShow16x16Hz(66, 48, 18, YELLOW, BLACK);
  61.   delay_ms(2000);
  62.   while(DS18B20_Init())        
  63.   {
  64.     printf("DS18B20温度传感器不存在\n");
  65.     LcdFill(0,0,128,160,BLACK);
  66.     LcdShowString(2,24,"DS18B20",RED, BLACK,16);
  67.     LcdShow16x16Hz(60, 24, 10, YELLOW, BLACK);
  68.     LcdShow16x16Hz(76, 24, 11, YELLOW, BLACK);
  69.     LcdShow16x16Hz(92, 24, 12, YELLOW, BLACK);
  70.     LcdShow16x16Hz(108, 24, 13, YELLOW, BLACK);
  71.     LcdShow16x16Hz(2, 48, 14, YELLOW, BLACK);
  72.     LcdShow16x16Hz(18, 48, 19, YELLOW, BLACK);
  73.     LcdShow16x16Hz(34, 48, 20, YELLOW, BLACK);
  74.     LcdShow16x16Hz(50, 48, 21, YELLOW, BLACK);
  75.     delay_ms(1000);
  76.   }
  77.   printf("检测到DS18B20温度传感器,并初始化成功\n");
  78.   LcdFill(0,0,128,160,BLACK);
  79.   LcdShow16x16Hz(2, 24, 22, YELLOW, BLACK);
  80.   LcdShow16x16Hz(18, 24, 23, YELLOW, BLACK);
  81.   LcdShow16x16Hz(34, 24, 24, YELLOW, BLACK);
  82.   LcdShowString(50,24,"DS18B20",RED, BLACK,16);
  83.   LcdShow16x16Hz(108, 24, 10, YELLOW, BLACK);
  84.   LcdShow16x16Hz(2, 48, 11, YELLOW, BLACK);
  85.   LcdShow16x16Hz(18, 48, 12, YELLOW, BLACK);
  86.   LcdShow16x16Hz(34, 48, 13, YELLOW, BLACK);
  87.   LcdShow16x16Hz(50, 48, 14, YELLOW, BLACK);
  88.   LcdShowString(66,48,",",YELLOW, BLACK,16);
  89.   LcdShow16x16Hz(74, 48, 25, YELLOW, BLACK);
  90.   LcdShow16x16Hz(90, 48, 26, YELLOW, BLACK);
  91.   LcdShow16x16Hz(106, 48, 27, YELLOW, BLACK);
  92.   LcdShow16x16Hz(2, 72, 28, YELLOW, BLACK);
  93.   LcdShow16x16Hz(18, 72, 29, YELLOW, BLACK);
  94.   LcdShow16x16Hz(34, 72, 30, YELLOW, BLACK);

  95.   DS18B20_ReadId(DS18B20ID);
  96.   printf("DS18B20的序列号是: 0x");  
  97.   for ( i = 0; i < 8; i ++ )            
  98.        printf ( "%.2X", DS18B20ID[i]);
  99.   printf("\n");
  100.         
  101.   sprintf(str,"0x%02X%02X%02X%02X%02X%02X%02X%02X",DS18B20ID[0],DS18B20ID[1],DS18B20ID[2],DS18B20ID[3],
  102.                                                                      DS18B20ID[4],DS18B20ID[5],DS18B20ID[6],DS18B20ID[7]);
  103.   
  104.   LcdShowString(8,96,"DS18B20",RED, BLACK,12);
  105.   LcdShow16x16Hz(50, 96, 32, YELLOW, BLACK);
  106.   LcdShow16x16Hz(66, 96, 33, YELLOW, BLACK);
  107.   LcdShow16x16Hz(82, 96, 34, YELLOW, BLACK);
  108.   LcdShow16x16Hz(98, 96, 35, YELLOW, BLACK);
  109.   LcdShow16x16Hz(114, 96, 40, YELLOW, BLACK);
  110.   LcdShowString(8,120,str,RED,BLACK,12);
  111.   delay_ms(2000);
  112.   while(1)
  113.   {
  114.     temperature = DS18B20_GetTemp_MatchRom(DS18B20ID);
  115.     /* 打印通过 DS18B20 序列号获取的温度值 */
  116.     printf("获取该序列号器件的温度:%.1f\n",temperature);
  117.     LcdFill(0,0,128,160,BLACK);
  118.     LcdShow16x16Hz(2, 8, 36, YELLOW, BLACK);
  119.     LcdShow16x16Hz(18, 8, 37, YELLOW, BLACK);
  120.     LcdShow16x16Hz(34, 8, 10, YELLOW, BLACK);
  121.     LcdShow16x16Hz(50, 8, 11, YELLOW, BLACK);
  122.     LcdShow16x16Hz(66, 8, 38, YELLOW, BLACK);
  123.     LcdShow16x16Hz(82, 8, 39, YELLOW, BLACK);
  124.     LcdShow16x16Hz(98, 8, 40, YELLOW, BLACK);
  125.     LCD_ShowFloatNum1(8,32,temperature,4,RED, BLACK,24);
  126.     LcdShow16x16Hz(70, 36, 41, RED, BLACK);
  127.     delay_ms(200);
  128.     if(temperature <= TEMP_THRESHOLD) {
  129.            tmr_output_enable(TMR3, FALSE);
  130.            gpio_bits_reset(GPIOB,GPIO_PINS_5);
  131.            gpio_bits_reset(GPIOB,GPIO_PINS_2);
  132.            gpio_bits_reset(GPIOB,GPIO_PINS_10);        
  133.      }else if (temperature-TEMP_THRESHOLD <= 0.5) {
  134.            // 启动风机逆时针旋转
  135.            gpio_bits_reset(GPIOB,GPIO_PINS_10);
  136.            gpio_bits_set(GPIOB,GPIO_PINS_2);
  137.            tmr_output_enable(TMR3, FALSE);
  138.            tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr1_val);
  139.            tmr_output_enable(TMR3, TRUE);
  140.            gpio_bits_toggle(GPIOB,GPIO_PINS_5);
  141.            delay_ms(500);
  142.       }else if(temperature-TEMP_THRESHOLD <= 1.5) {
  143.             tmr_output_enable(TMR3, FALSE);
  144.             tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr2_val);
  145.             tmr_output_enable(TMR3, TRUE);
  146.             gpio_bits_toggle(GPIOB,GPIO_PINS_5);
  147.             delay_ms(200);
  148.        }else if(temperature-TEMP_THRESHOLD <= 2.5) {
  149.             tmr_output_enable(TMR3, FALSE);
  150.             tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr3_val);
  151.             tmr_output_enable(TMR3, TRUE);
  152.             gpio_bits_toggle(GPIOB,GPIO_PINS_5);
  153.             delay_ms(50);
  154.         }else if(temperature-TEMP_THRESHOLD <= 3.5) {
  155.              tmr_output_enable(TMR3, FALSE);
  156.              tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_4, ccr4_val);
  157.              tmr_output_enable(TMR3, TRUE);
  158.              gpio_bits_toggle(GPIOB,GPIO_PINS_5);
  159.              delay_ms(10);
  160.          }
  161.          else {
  162.               tmr_output_enable(TMR3, FALSE);
  163.               gpio_bits_reset(GPIOB,GPIO_PINS_5);
  164.               gpio_bits_reset(GPIOB,GPIO_PINS_2);
  165.               gpio_bits_reset(GPIOB,GPIO_PINS_10);        
  166.          }
  167.     }
  168. }
        根据以上代码可知,温度门限控制在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开发板评测活动]内容优质

梦境漫游者 发表于 2025-8-21 11:16 | 显示全部楼层
这个电机模块看上去好古老啊,应该是有刷电机驱动
NebulaHaven 发表于 2025-8-21 11:58 | 显示全部楼层
这个电机就是用来散热对吧,温度一高就转起来。
 楼主| yinwuqing110 发表于 2025-8-21 14:14 | 显示全部楼层
梦境漫游者 发表于 2025-8-21 11:16
这个电机模块看上去好古老啊,应该是有刷电机驱动

是有刷直流电机,无刷不是这样的。
 楼主| yinwuqing110 发表于 2025-8-21 14:15 | 显示全部楼层
NebulaHaven 发表于 2025-8-21 11:58
这个电机就是用来散热对吧,温度一高就转起来。

是的,是这个原理
您需要登录后才可以回帖 登录 | 注册

本版积分规则

106

主题

1098

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部