注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
lugl4313820的个人空间 http://home.eeworld.com.cn/space-uid-1269709.html [收藏] [复制] [分享] [RSS]
日志

【沁恒RISC-V内核 CH582】恒温控制取暖器

已有 206 次阅读2022-4-12 07:32

前一陈子,用手机APP控制取暖器:【沁恒RISC-V内核 CH582】PWM 控制取暖器 - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn),结合我参与迪文屏的活动,也制作了一个恒温的取暖器,这里展示一下给大家:

【实现控制原理】迪文屏由UART0与CH582进行通信,发送开、关,或者预期温度值。CH582运行TMOS进行串口接收与AHT10的温度值进行采样,组成温度控制系统。

【迪文屏实现步聚】:

1、制作背景图片:

2、设置按键变量等如下图:

具体实现在这里不是重点,我附具体工程在后面。

【CH582】实现方式:

1、UART0与迪文屏进行通信,首先初始化迪文屏,中断接收。同时初始化定时器1,实现1ms产生一个中断,进行计时:

/*
 * 初始串口0、1
 */
void SerialInit(void)
{
  /* 配置串口1:先配置IO口模式,再配置串口 */
    GPIOA_SetBits( GPIO_Pin_9 );
    GPIOA_ModeCfg( GPIO_Pin_8, GPIO_ModeIN_PU );      // RXD-配置上拉输入
    GPIOA_ModeCfg( GPIO_Pin_9, GPIO_ModeOut_PP_5mA );    // TXD-配置推挽输出,注意先让IO口输出高电平
    UART1_DefInit();

    //继电器加热工作输出
    GPIOB_SetBits(GPIO_Pin_19);
    GPIOB_ModeCfg(GPIO_Pin_19, GPIO_ModeOut_PP_20mA);

    /* 配置串口0:先配置IO口模式,再配置串口 */
   GPIOB_SetBits( GPIO_Pin_7);
   GPIOB_ModeCfg( GPIO_Pin_4, GPIO_ModeIN_PU );      // RXD-配置上拉输入
   GPIOB_ModeCfg( GPIO_Pin_7, GPIO_ModeOut_PP_5mA );    // TXD-配置推挽输出,注意先让IO口输出高电平
   UART0_DefInit();

   UART0_ByteTrigCfg( UART_1BYTE_TRIG ); //这里设置接收到1字节就产生中断,实现不定长接收
   UART0_INTCfg( ENABLE, RB_IER_RECV_RDY|RB_IER_LINE_STAT );
   PFIC_EnableIRQ( UART0_IRQn );

   TMR0_TimerInit(FREQ_SYS / 1000);         // 设置定时时间 1ms
   TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END); // 开启中断
   PFIC_EnableIRQ(TMR0_IRQn);
}

2、定义UART0中断函数:

__INTERRUPT
__HIGH_CODE

void UART0_IRQHandler( void )
{
  UINT8 ch;
  switch ( UART0_GetITFlag() )
  {
    case UART_II_LINE_STAT :        // 线路状态错误
    {
      UART0_GetLinSTA();
      break;
    }

    case UART_II_RECV_RDY :          // 数据达到设置触发点
      ch=UART0_RecvByte();
      Serial0Recv(ch);
      break;

    case UART_II_RECV_TOUT :         // 接收超时,暂时一帧数据接收完成
      break;

    case UART_II_THR_EMPTY :         // 发送缓存区空,可继续发送
      break;

    case UART_II_MODEM_CHG :         // 只支持串口0
      break;

    default :
      break;
  }

}

3、定时器1函数

__INTERRUPT
__HIGH_CODE
void TMR0_IRQHandler( void )        // TMR0 定时中断
{
  if ( TMR0_GetITFlag( TMR0_3_IT_CYC_END ) )
  {
    TMR0_ClearITFlag( TMR0_3_IT_CYC_END );      // 清除中断标志
    SerialRecvTimeout();  //1ms时间到了去检测是否超时
  }
}

4、迪文屏串口接收、处理:

void task_uart0_rec(void)
{
    int i , l;
    if (SerialStr0.RecvLen > 0  ) {
        PRINT("RECV_LEN:%d",SerialStr0.RecvLen);
        if (SerialStr0.RecvLen == (SerialStr0.RecvBuff[2]+3) \
                && SerialStr0.RecvBuff[0] == 0x5A \
                && SerialStr0.RecvBuff[1] == 0xA5)
        {
           //接收到正确的数据
            DMG85480.state = RECV_WAIT_EXPLAN;
            DMG85480.data_len = SerialStr0.RecvBuff[2]-3;

            DMG85480.commad = SerialStr0.RecvBuff[3];
            PRINT("recv_CMMD:%X\n",DMG85480.commad);
            DMG85480.address  = (uint16_t)SerialStr0.RecvBuff[4]<<8 | SerialStr0.RecvBuff[5];
            PRINT("recv_ADDRS:%X\n",DMG85480.address);
            i = SerialStr0.RecvBuff[2]-3;
            for (l = 0; l < i; ++l) {
                DMG85480.data[l] = SerialStr0.RecvBuff[l+6];
            }
            rev_explain();
            DMG85480.DMG_ERROR = RECV_OK;
        }
        else {
            DMG85480.DMG_ERROR = RECV_ERR;
            SerialStr0.RecvLen = 0;//丢弃无效的包
        }
    }
    SerialStr0.RecvLen = 0;
}

5、迪文屏命令处理:

/*
 * 数据判断
 *
 */
static void  rev_explain(void)
{
    uint8_t send_data[10];
    switch (DMG85480.commad) {
        case WRIT_DMG_DATA:
            if (DMG85480.address == SWITCH) {//如果是开关按键
                if (DMG85480.data[2] == 0x01) {//按下的是开键,转换到页面。
                    PRINT("OPEN\n");
                    Electric_Heater.work_state = OPEN;
                    send_data[0] = 0x5A;
                    send_data[1] = 0x01;
                    send_data[2] = 0x00;
                    send_data[3] = 0x01;
                    DMG85480.state = IDEL;
                    send_DMG(send_data, CHANG_PAGE, WRIT_DMG_CMD,4);
                    //等待收到OK
                    //设置开机模式
                }
                else if (DMG85480.data[2] == 0x00) { //关断了
                    //关闭电加热丝 切换到0号页面
                    Electric_Heater.work_state = CLOSE;
                    PRINT("CLOSE\n");
                    send_data[0] = 0x5A;
                    send_data[1] = 0x01;
                    send_data[2] = 0x00;
                    send_data[3] = 0x00;
                    DMG85480.state = IDEL;
                    send_DMG(send_data, CHANG_PAGE, WRIT_DMG_CMD,4);
                }
            }
            else if (DMG85480.address == SET_TEMP) { //温度设定改变
                //设置温度值
                PRINT("CHANGE\n");
                Electric_Heater.set_temp = DMG85480.data[2];
                DMG85480.state = IDEL;
            }
        break;
        case WRIT_DMG_CMD:
            if (DMG85480.address == SEND_RECV_OK) {//返回写正确
                    DMG85480.DMG_ERROR = SEND_OK;
                    DMG85480.state = IDEL;

            }
            break;
        default:
        break;
    }
}

7、迪文屏发送函数封装:

/*
 * 发送给串口屏
 * 参数1:数据
 * 参数2:指令 0x80-0x83
 * 参数3:串口屏地址
 * 参数4:数据长度
 */
void send_DMG(uint8_t pdata[], uint16_t addr, uint8_t commd, uint8_t data_len)
{
  uint8_t commd_len;
  while(DMG85480.state != IDEL);
  SerialStr0.TxBuff[0] = 0x5a;
  SerialStr0.TxBuff[1] = 0xa5;
  SerialStr0.TxBuff[2] = data_len + 3;//长度
  SerialStr0.TxBuff[3] = commd;
  SerialStr0.TxBuff[4] = (uint8_t)(addr>>8);
  SerialStr0.TxBuff[5] = (uint8_t)addr;
  for (commd_len = 0; commd_len < data_len; ++commd_len) {
      SerialStr0.TxBuff[6+commd_len] = pdata[commd_len];
  }
  DMG85480.state = SEND_WAIT;
  UART0_SendString(SerialStr0.TxBuff, 6+data_len);
  DMG85480.state = IDEL;
}

【AHT10温度采集】AHT10每1秒采集一次环境温度,更新到取暖器的当前温度值,与设置温度进行对比,来确定继电器的开关。

//加热器状况
typedef struct{
    uint8_t work_state; //是否打开
    uint8_t set_temp; //期望温度
    uint8_t this_temp; //目前温度值
    uint8_t old_temp;
    uint32_t work_time; //工作时间
    uint32_t stop_work_time; //休息时间
    uint32_t next_work_time; //等待时间
} _Electric_Heater;
【取暖器控制】1、先判断work_state,如果来确定是否打开关闭继电器。

2、如果开的状态,则比较当前温度与预设温度,来确定开关的状态。

_Electric_Heater Electric_Heater;

void select_working_mode(void)
{
    if (Electric_Heater.this_temp < Electric_Heater.set_temp && Electric_Heater.work_state == OPEN)
    {
        Electric_Heater.work_state = OPEN;
    } else if (Electric_Heater.this_temp > Electric_Heater.set_temp && Electric_Heater.work_state == OPEN) {
        Electric_Heater.work_state = WAITING;
        Electric_Heater.stop_work_time = 5;
    }
    else if (Electric_Heater.work_state == WAITING && Electric_Heater.stop_work_time>0 ) {
        Electric_Heater.work_state = WAITING;
        Electric_Heater.stop_work_time --;
       // mDelaymS(1000);
    }
    else if (Electric_Heater.work_state == WAITING && Electric_Heater.stop_work_time == 0 )
    {
        Electric_Heater.work_state = OPEN;
    }
}

3、继电器工作任务函数:

void select_hearter_work(void)
{
    //继电器加热工作输出
    static uint8_t old_temp;
       //void send_DMG(uint8_t pdata[], uint16_t addr, uint8_t commd, uint8_t data_len)
        uint8_t temp[10] = {0};
        if (Electric_Heater.work_state != CLOSE) {
            if (Electric_Heater.this_temp != Electric_Heater.old_temp) {
                Electric_Heater.old_temp = Electric_Heater.this_temp;
                temp[1] = Electric_Heater.this_temp;
                send_DMG(temp,DISP_TEMP,WRIT_DMG_CMD,2);
            }
            temp[0] = 0x5a;
            temp[1] = 0xa5;
            temp[2] = 0x01;
            temp[3] = 0x00;//0通道
            temp[4] = 0x00;
            temp[5] = 0x01;//1个数据
            temp[6] = 0x00;
            temp[7] = Electric_Heater.this_temp;
            send_DMG(temp,LINE_ADDR,WRIT_DMG_CMD,8);
        }
        select_working_mode();

        if (Electric_Heater.work_state == OPEN) {
            //开启加热
            PRINT("STATE == OPEN\n");
            GPIOB_SetBits(GPIO_Pin_19);
        }
        else {
            PRINT("STATE == CLOSE\n");
            GPIOB_ResetBits(GPIO_Pin_19);
        }
        select_working_mode();
}

【TMOS任务创建】:1、创建任务ID、事件函数

static uint8_t Peripheral_TaskID = INVALID_TASK_ID; // Task ID for internal task/event processing
static uint8_t AH10_TaskID = AH10_EVT;
static uint8_t DMG_TaskID = DMG_EVT;
static uint8_t HEATER_TaskID = HEATER_EVT;

uint16_t AH10_ProcessEvent(uint8_t task_id, uint16_t events);
uint16_t DMG_ProcessEvent(uint8_t task_id, uint16_t events);
uint16_t HEATER_ProcessEvent(uint8_t task_id, uint16_t events);

2、入口函数:

uint16_t AH10_ProcessEvent(uint8_t task_id, uint16_t events)
{

    if ( events & AH10_EVT ) {
        AHT10ReadData(temperate,humidity);
        return (events ^ AH10_EVT);
    }
    return 0;
}

uint16_t DMG_ProcessEvent(uint8_t task_id, uint16_t events)
{
    if ( events & DMG_EVT ) {
        dmg_work();
        return (events ^ DMG_EVT);
      }
      return 0;
}

uint16_t HEATER_ProcessEvent(uint8_t task_id, uint16_t events)
{
    if ( events & HEATER_EVT ) {
        select_hearter_work();
         return (events ^ HEATER_EVT);
      }
      return 0;
}

3、主任务添加循环调用的命令:

tmos_start_reload_task(DMG_TaskID, DMG_EVT, 500);//迪文屏通讯任务
tmos_start_reload_task(AH10_TaskID,AH10_EVT,1600);//温度采集
tmos_start_reload_task(HEATER_TaskID, HEATER_EVT, 6000);//继电器控制

【实现效果】:


 

本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册