打印
[AT32M412]

【AT-START-M412测评】+孵化控制器

[复制链接]
93|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 gaoyang9992006 于 2025-6-16 12:42 编辑

【AT-START-M412测评】+给开发板做了一个扩展板                       https://bbs.21ic.com/icview-3461506-1-1.html
【AT-START-M412测评】+ 按钮学习,IO中断,为何下降沿不中断    https://bbs.21ic.com/icview-3461522-1-1.html
【AT-START-M412测评】+ 按钮学习,多路IO中断                            https://bbs.21ic.com/icview-3461668-1-1.html
【AT-START-M412测评】+点亮SSD1306的OLED屏                            https://bbs.21ic.com/icview-3461734-1-1.html

经过今天一上午的学习和实验,终于将之前我做过的东西合并成了一个 可以用的鸡蛋孵化控制器。
该电路包含了四部分:IO输入中断功能实现的按键部分;I2C接口的显示器部分;ADC检测NTC温度传感器部分;IO输出控制部分。

总体main.c代码如下所示


#include "at32m412_416_board.h"
#include "at32m412_416_clock.h"
#include "i2c_application.h"
#include "oled.h"
#include "at32m412_416_adc.h"
        #include  "NTC.h"


extern i2c_handle_type hi2cx;


#define DELAY                            100
#define FAST                             1
#define SLOW                             4

uint8_t g_speed = FAST;
uint8_t ioIndex =0x00;
void button_exint_init(void);

void button_B4_isr(void);
void button_B5_isr(void);
void button_B7_isr(void);
void button_B10_isr(void);

void Write_IIC_Command(unsigned char IIC_Command);
void Write_IIC_Data(unsigned char IIC_Data);
void OLED_WR_Byte(unsigned dat,unsigned cmd);
void i2c_lowlevel_init(i2c_handle_type* hi2c);


/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  configure button exint
  * @param  none
  * @retval none
  */
//void button_exint_init(void)
//{
//  exint_init_type exint_init_struct;

//  crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE);
//   scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOA, SCFG_PINS_SOURCE0);

//  exint_default_para_init(&exint_init_struct);
//  exint_init_struct.line_enable = TRUE;
//  exint_init_struct.line_mode = EXINT_LINE_INTERRUPT;
//  exint_init_struct.line_select = EXINT_LINE_0;
//  exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
//  exint_init(&exint_init_struct);

//  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
//  nvic_irq_enable(EXINT0_IRQn, 0, 0);
//}
void button_exint_init(void)
{
  exint_init_type exint_init_struct;

  crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE);
  scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOB, SCFG_PINS_SOURCE4);
  scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOB, SCFG_PINS_SOURCE5);  
  scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOB, SCFG_PINS_SOURCE7);
  scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOB, SCFG_PINS_SOURCE10);
  
  exint_default_para_init(&exint_init_struct);
  exint_init_struct.line_enable = TRUE;
  exint_init_struct.line_mode = EXINT_LINE_INTERRUPT;
  exint_init_struct.line_select = EXINT_LINE_4 | EXINT_LINE_5 | EXINT_LINE_7 | EXINT_LINE_10;
  exint_init_struct.line_polarity = EXINT_TRIGGER_FALLING_EDGE;
  exint_init(&exint_init_struct);
  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  nvic_irq_enable(EXINT4_IRQn, 0, 0);
  nvic_irq_enable(EXINT9_5_IRQn, 0, 0);
  nvic_irq_enable(EXINT15_10_IRQn, 0, 0);
}
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  button handler function
  * @param  none
  * @retval none
  */
void button_B4_isr(void)
{
  /* delay 5ms */
  delay_ms(5);

  /* clear interrupt pending bit */
  exint_flag_clear(EXINT_LINE_4);

  /* check input pin state */
  if(RESET == gpio_input_data_bit_read(GPIOB, GPIO_PINS_4))
  {
    ioIndex = 0x03;
  }
  printf("GPIOB_04 is pressed.\r\n");
}

void button_B5_isr(void)
{
  /* delay 5ms */
  delay_ms(5);

  /* clear interrupt pending bit */
  exint_flag_clear(EXINT_LINE_5);

  /* check input pin state */
  if(RESET == gpio_input_data_bit_read(GPIOB, GPIO_PINS_5))
  {
    ioIndex = 0x04;
    printf("GPIOB_05 is pressed.\r\n");
  }

}

void button_B7_isr(void)
{
  /* delay 5ms */
  delay_ms(5);

  /* clear interrupt pending bit */
  exint_flag_clear(EXINT_LINE_7);

  /* check input pin state */
  if(RESET == gpio_input_data_bit_read(GPIOB, GPIO_PINS_7))
  {
    ioIndex = 0x01;
    printf("GPIOB_07 is pressed.\r\n");
  }
  
}

void button_B10_isr(void)
{
  /* delay 5ms */
  delay_ms(5);

  /* clear interrupt pending bit */
  exint_flag_clear(EXINT_LINE_10);

  /* check input pin state */
  if(RESET == gpio_input_data_bit_read(GPIOB, GPIO_PINS_10))
  {
    ioIndex = 0x02;   
    printf("GPIOB_10 is pressed.\r\n");
  }

}


/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  exint0 interrupt handler
  * @param  none
  * @retval none
  */
void EXINT4_IRQHandler(void)
{
  button_B4_isr();
}
void EXINT9_5_IRQHandler(void)
{
  button_B5_isr();
  button_B7_isr();
}
void EXINT15_10_IRQHandler(void)
{
  button_B10_isr();
}

void disp_static(void)
{
                u8 i;
        
                for(i=0; i<5; i++)        WriteHZ16((u8)(i*16+24), 0,i);                //在第1行,显示汉字“科学小火箭”
                for(i=5; i<7; i++)        WriteHZ16((u8)((i-5)*16),2,i);                //在第2行,显示汉字“设置”
                for(i=9; i<11; i++)        WriteHZ16((u8)((i-7)*16),2,i);                //在第2行,显示汉字“温度”
               
                WriteHZ16((u8)(7*16),2,13);                                       //在第2行末尾,显示“℃”
                WriteHZ16((u8)(7*16),4,13);                                       //在第3行末尾,显示“℃”
        
                for(i=7; i<11; i++)        WriteHZ16((u8)((i-7)*16),4,i);                //在第3行,显示汉字“当前温度”
               
                WriteHZ16(0,6,11);                                                //在第4行,显示汉字“第”
                WriteHZ16(48,6,12);                                               //在第4行,显示汉字“天”
}

static void gpio_config(void)
{
  gpio_init_type gpio_initstructure;
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  gpio_default_para_init(&gpio_initstructure);

  /* 1. 配置ADC引脚(PA1)为模拟输入模式 */
  gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG;
  gpio_initstructure.gpio_pins = GPIO_PINS_1;
  gpio_init(GPIOA, &gpio_initstructure);
  
  /* 2. 配置PA6为推挽输出模式 */
  gpio_default_para_init(&gpio_initstructure); // 重新初始化结构体
  gpio_initstructure.gpio_pins = GPIO_PINS_6;
  gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
  gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_pull = GPIO_PULL_NONE;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init(GPIOA, &gpio_initstructure);
  
  // 可选:初始化PA6为低电平
  gpio_bits_reset(GPIOA, GPIO_PINS_6);
  
}

static void adc_config(void)
{
  adc_common_config_type adc_common_struct;
  adc_base_config_type adc_base_struct;
  crm_periph_clock_enable(CRM_ADC2_PERIPH_CLOCK, TRUE);

  adc_common_default_para_init(&adc_common_struct);

  /* config combine mode */
  adc_common_struct.combine_mode = ADC_INDEPENDENT_MODE;

  /* config division,adcclk is division by hclk */
  adc_common_struct.div = ADC_HCLK_DIV_6;

  /* config common dma mode,it's not useful in independent mode */
  adc_common_struct.common_dma_mode = ADC_COMMON_DMAMODE_DISABLE;

  /* config common dma request repeat */
  adc_common_struct.common_dma_request_repeat_state = FALSE;

  /* config adjacent adc sampling interval,it's useful for ordinary shifting mode */
  adc_common_struct.sampling_interval = ADC_SAMPLING_INTERVAL_4CYCLES;

  /* config inner temperature sensor and vintrv */
  adc_common_struct.tempervintrv_state = FALSE;
  adc_common_config(&adc_common_struct);

  adc_base_default_para_init(&adc_base_struct);

  adc_base_struct.sequence_mode = TRUE;
  adc_base_struct.repeat_mode = FALSE;
  adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
  adc_base_struct.ordinary_channel_length = 1;
  adc_base_config(ADC2, &adc_base_struct);
  adc_resolution_set(ADC2, ADC_RESOLUTION_12B);

  /* config ordinary channel */
  adc_ordinary_channel_set(ADC2, ADC_CHANNEL_1, 1, ADC_SAMPLETIME_239_5);

  /* adc enable */
  adc_enable(ADC2, TRUE);
  while(adc_flag_get(ADC2, ADC_RDY_FLAG) == RESET);

  /* adc calibration */
  adc_calibration_init(ADC2);
  while(adc_calibration_init_status_get(ADC2));
  adc_calibration_start(ADC2);
  while(adc_calibration_status_get(ADC2));
}
/**
  * @brief  main function.
  * @param  none
  * @retval none

  */

float target_temperature  = 37.8;
float current_temperature = 0;
u8    target_temperature_string[5];//存储目标温度字符串
u8    current_temperature_string[5];//存储当前温度字符串

u8     day_s[3];       //存储天数字符串
u8     adc_temp[5];
u16    adc_result=0;
float Rval;

int time_ms  =0;
int time_s   =50;
int time_min =59;
int time_hour=23;
int time_days=5;

int flag_s = 0;

u8 time_char[9]="12:23:45";//用于存储显示用的 时:分:秒

crm_clocks_freq_type crm_clocks_freq_struct = {0};

int main(void)
{
  system_clock_config();

  at32_board_init();
  button_exint_init();
  gpio_config();
  adc_config();
  hi2cx.i2cx = I2Cx_PORT;
  i2c_config(&hi2cx);
  
  uart_print_init(115200);
  printf("at32 mcu initialize ok.\r\n");
  Initialize_OLED();
  disp_static();
  
  /* get system clock */
  crm_clocks_freq_get(&crm_clocks_freq_struct);
  /* enable tmr1 clock */
  crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
  /* tmr1 configuration */
  /* time base configuration */
  tmr_base_init(TMR1, 999, (crm_clocks_freq_struct.apb2_freq / 1000000) - 1);
  tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);

  /* overflow interrupt enable */
  tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);

  /* tmr1 hall interrupt nvic init */
  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 1, 0);
    /* enable tmr1 */
  tmr_counter_enable(TMR1, TRUE);
  while(1)
  {
//    at32_led_toggle(LED2);
//    delay_ms(g_speed * DELAY);
//    at32_led_toggle(LED3);
//    delay_ms(g_speed * DELAY);
//    at32_led_toggle(LED4);
//    delay_ms(g_speed * DELAY);

                if(ioIndex==0x01)
                {
                        time_days--;
                        if(time_days<=0) time_days=0;
                        ioIndex=0x00;
                }
               
                if(ioIndex==0x02)
                {
                        time_days++;
                        if(time_days>=50) time_days=0;
                        ioIndex=0x00;
                }        
               
                if(ioIndex==0x03)
                {
                        target_temperature=target_temperature - 0.1;
                        ioIndex=0x00;
                }
               
                if(ioIndex==0x04)
                {
                        target_temperature=target_temperature + 0.1;
                        ioIndex=0x00;
                }        

                        if(target_temperature>40.5) target_temperature=37.9;
                        if(target_temperature<32.0) target_temperature=37.8;
   
//计算当前温度               
    adc_ordinary_software_trigger_enable(ADC2, TRUE);
    while(!adc_flag_get(ADC2, ADC_OCCE_FLAG));
    adc_flag_clear(ADC2, ADC_OCCE_FLAG);
    adc_result = adc_ordinary_conversion_data_get(ADC2);
   
                Rval=(adc_result*6200.0)/(4095.0-adc_result);
    current_temperature = Res_to_Tem(Rval);
    if(current_temperature>= 99.0)  current_temperature =  99.0;
    if(current_temperature<=-30.0) current_temperature  = -30.0;
   
  //简单粗暴,如果温度低于目标温度就加温否则就不加温
        if(current_temperature<target_temperature)
        {
          gpio_bits_set(GPIOA, GPIO_PINS_6);
        }
        else
        {
          gpio_bits_reset(GPIOA, GPIO_PINS_6);
        }
   
    if(flag_s)
                {
                        flag_s=0;
                        
                        sprintf((char*)target_temperature_string,  "%2.1f",  target_temperature);  // 格式化为保留一位小数的字符串        
                        sprintf((char*)current_temperature_string, "%2.1f", current_temperature);  // 格式化为保留一位小数的字符串
                        sprintf((char*)day_s, "%02d", time_days);
                        sprintf((char*)time_char,"%02d:%02d:%02d",time_hour,time_min,time_s);
                  sprintf((char*)adc_temp, "%04d", adc_ordinary_conversion_data_get(ADC2));
        

                        printf_ASCII_16_text(64+8,2,target_temperature_string);                              //在第2行,显示设置的目标温度数值
                        printf_ASCII_16_text(64+8,4,"     ");
                        printf_ASCII_16_text(64+8,4,current_temperature_string);                             //在第3行,显示当前采集的温度数值
                  printf_ASCII_16_text(64,6,time_char);                                //在第4行,显示“时分秒”
        //                printf_ASCII_16_text(64+16,6,adc_temp);                            //在第4行,显示ADC测试值
                        printf_ASCII_16_text(24,6,day_s);                                //在第4行,显示天数
        //  FillAll(0);
                }
   
  }
}

void TMR1_OVF_TMR10_IRQHandler(void)
{
  if(tmr_interrupt_flag_get(TMR1, TMR_OVF_FLAG) == SET)
  {
    time_ms++;
    if(time_ms>=1000)
    {
      time_ms=0;
      time_s++;
      flag_s=1;//用于动态刷新,每秒1次
      if(time_s>=60)
      {
        time_s=0;
        time_min++;
        if(time_min>=60)
        {
          time_min=0;
          time_hour++;
          if(time_hour>=24)
          {
            time_hour=0;
            time_days++;
            if(time_days>99) time_days=0;
          }
        }
      }
    }
    tmr_flag_clear(TMR1, TMR_OVF_FLAG);
  }
}





void i2c_lowlevel_init(i2c_handle_type* hi2c)
{
  gpio_init_type gpio_init_structure;
  if(hi2c->i2cx == I2Cx_PORT)
  {
    crm_periph_clock_enable(I2Cx_CLK, TRUE);
    crm_periph_clock_enable(I2Cx_SCL_GPIO_CLK, TRUE);
    crm_periph_clock_enable(I2Cx_SDA_GPIO_CLK, TRUE);
    gpio_pin_mux_config(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_GPIO_PinsSource, I2Cx_SCL_GPIO_MUX);
    gpio_pin_mux_config(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_GPIO_PinsSource, I2Cx_SDA_GPIO_MUX);
    gpio_init_structure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_structure.gpio_mode = GPIO_MODE_MUX;
    gpio_init_structure.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
    gpio_init_structure.gpio_pull = GPIO_PULL_UP;
    gpio_init_structure.gpio_pins = I2Cx_SCL_GPIO_PIN;
    gpio_init(I2Cx_SCL_GPIO_PORT, &gpio_init_structure);
    gpio_init_structure.gpio_pins = I2Cx_SDA_GPIO_PIN;
    gpio_init(I2Cx_SDA_GPIO_PORT, &gpio_init_structure);
    i2c_init(hi2c->i2cx, 0x0F, I2Cx_CLKCTRL);
  }
}


测试视频

https://www.bilibili.com/video/BV1u6MvzHEQR?t=2.4
官方 的库函数有点多,需要配合手册才好理解。另外PWM也非常好用,需要慢慢掌握外设的配置方式和官方的库函数使用方法。


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2028

主题

16278

帖子

218

粉丝