Ritchie 发表于 2025-5-20 10:28:15

11F02E通过IO口控制继电器,通过串口收到数据,继电器不动作,串口通信正常

#include "reg51.h"
#include "intrins.h"

typedef unsigned char BYTE;
typedef unsigned int WORD;

#define FOSC 22118400L
#define BAUD 9600

/* 指令格式定义 */
#define CMD_HEAD 0xFF      // 指令头
#define CMD_TAIL 0xEE      // 指令尾
#define RELAY_ALL 0x25   // 全继电器操作码
#define ACTION_OFF 0x00    // 断开动作
#define ACTION_ON 0x01   // 闭合动作
#define ACTION_PULSE 0x02// 点动动作

BYTE rxBuffer;          // 接收缓冲区
BYTE rxIndex = 0;          // 接收索引
bit cmdReady = 0;          // 指令就绪标志

/* 继电器控制引脚定义 */
sbit Relay1 = P3^3;      // 第1路继电器
sbit Relay2 = P3^4;      // 第2路继电器
sbit Relay3 = P1^2;      // 第3路继电器
sbit Relay4 = P1^5;      // 第4路继电器

/* 定时器相关变量 */
WORD pulseTimer = 0;       // 点动计时器
bit pulseActive = 0;       // 点动激活标志

sfr AUXR1 = 0xA2;          // STC单片机扩展寄存器
sfr P1M0 = 0x92; // 0000,0000
sfr P1M1 = 0x91; //0000,0000
sfr P3M0 = 0xB2; //0000,0000
sfr P3M1 = 0xB1; // 0000,0000
#define UART_P1 0x80       // AUXR1.7位控制UART引脚切换

bit busy;

void SendData(BYTE dat);
void UART_Init();
void ProcessCommand();
void SetRelay(BYTE relay, BYTE state);
void Timer0_Init();

/******************** 主函数 ********************/
void main() {
      
//                P1M0 |= 0x12;//设置推挽输出
//    P1M1 &= 0xED;
//                P3M0 |= 0x0C;
//    P3M1 &= 0xF3;
      
//                P1M0 = 0x00;
//    P1M1 = 0x00;
//                P3M0 = 0x00;
//    P3M1 = 0x00;
      

    P3M0 |= 0x18; P3M1 &= ~0x18;
    P1M0 |= 0x24; P1M1 &= ~0x24;



                AUXR1 |= UART_P1;          // 切换UART到P1.6和P1.7
    UART_Init();         // 初始化串口
    Timer0_Init();         // 初始化定时器0
    EA = 1;                // 开启总中断

    while(1) {
      if(cmdReady) {   // 检测到完整指令
            cmdReady = 0;
            ProcessCommand();
      }
      if(pulseActive && !pulseTimer) { // 点动时间到
            pulseActive = 0;
            SetRelay(RELAY_ALL, ACTION_OFF); // 关闭所有继电器
      }
    }
}

/******************** 串口初始化 ********************/
void UART_Init() {
    SCON = 0x50;          // 模式1,允许接收
    TMOD |= 0x20;         // 定时器1模式2
    TH1 = TL1 = -(FOSC/12/32/BAUD);
    TR1 = 1;
    ES = 1;               // 启用串口中断
}

/******************** 定时器0初始化 ********************/
void Timer0_Init() {
    TMOD |= 0x01;         // 模式1(16位定时器)
    TH0 = 0xF8;         // 22.1184MHz下1ms定时
    TL0 = 0xCD;
    ET0 = 1;            // 允许定时器0中断
    TR0 = 1;
}

/******************** 串口中断服务 ********************/
void UART_ISR() interrupt 4 {
    if(RI) {
      RI = 0;
      rxBuffer = SBUF; // 存入接收缓冲区
      SendData(SBUF);
                        
      /* 指令完整性检查 */
      if(rxIndex == 1 && rxBuffer != CMD_HEAD)
            rxIndex = 0;// 无效包头则重置
      else if(rxIndex >= 5) {
            rxIndex = 0;
            if(rxBuffer == CMD_TAIL) cmdReady = 1; // 有效指令
      }
    }
    if (TI)
    {
      TI = 0;             //Clear transmit interrupt flag
      busy = 0;         //Clear transmit busy flag
    }
}

/******************** 定时器0中断服务 ********************/
void Timer0_ISR() interrupt 1 {
    TH0 = 0xF8;         // 重装初值
    TL0 = 0xCD;
    if(pulseTimer) pulseTimer--;
}

/******************** 继电器控制函数 ********************/
void SetRelay(BYTE relay, BYTE state) {
    switch(relay) {
      case 0x01: Relay1 = (state == ACTION_ON); break;
      case 0x02: Relay2 = (state == ACTION_ON); break;
                              case 0x03: Relay3 = (state == ACTION_ON); break;
                              case 0x04: Relay4 = (state == ACTION_ON); break;
      case RELAY_ALL:    // 全继电器操作
            Relay1 = (state == ACTION_ON);
                                    Relay2 = (state == ACTION_ON);
                                    Relay3 = (state == ACTION_ON);
                                    Relay4 = (state == ACTION_ON);
            break;
    }
}

/******************** 指令处理函数 ********************/
void ProcessCommand() {
                BYTE relay = rxBuffer;
    BYTE action = rxBuffer;
      
    /* 校验检查 */
    if((rxBuffer + rxBuffer) != rxBuffer) return;

    switch(action) {
      case ACTION_OFF:   // 断开
            SetRelay(relay, ACTION_OFF);
            break;

      case ACTION_ON:    // 闭合
            SetRelay(relay, ACTION_ON);
            break;

      case ACTION_PULSE: // 点动
            SetRelay(relay, ACTION_ON);
            pulseTimer = 1000;// 1000ms = 1s
            pulseActive = 1;
            break;
    }
}

void SendData(BYTE dat)
{
    while (busy);         //Wait for the completion of the previous data is sent
    busy = 1;
    SBUF = dat;             //Send data to UART buffer
}

国芯人工智能 发表于 2025-5-20 10:33:00

国芯AI控制继电器的实现

在当前的国芯AI系统中,控制继电器的逻辑设计需要结合STM32的 Distancetags 和串口通信的特点。以下是一段专业的国芯AI控制继电器的实现文档,供参考:

1. 目标与需求
本设计旨在通过国芯AI实现继电器的控制功能,支持全继电器(4个)的控制,同时结合串口通信,实现继电器动作的响应。

2. 基础知识回顾
STM32 Distancetags:STM32的 Distancetags 用于编码器的串口通信,支持全继电器(4个)的控制。
串口通信:通过串口通信实现继电器的动作响应,但需要结合 Distancetags 的数据进行处理。

3. 控制逻辑设计
3.1 引脚定义
以下定义了继电器的引脚:
c
sbit Relay1 = P3^3;      // 第1路继电器
sbit Relay2 = P3^4;      // 第2路继电器
sbit Relay3 = P1^2;      // 第3路继电器
sbit Relay4 = P1^5;      // 第4路继电器

3.2 系统变量定义
以下定义了系统变量:
c
WORD pulseTimer = 0;       // 点动计时器
bit pulseActive = 0;       // 点动激活标志
BYTE rxBuffer;          // 接收缓冲区
BYTE rxIndex = 0;          // 接收索引
bit cmdReady = 0;          // 指令就绪标志

4. 控制策略
1. 串口通信:通过串口通信获取继电器的状态信息。
2. 状态转换:将串口数据转换为控制信号(如动作、不动作等)。
3. 计时与动作:根据计时器的响应时间,确定继电器的动作动作。

5. 具体实现步骤
1. 初始化:将 pulseActive 设为 0,启动计时器。
2. 串口数据获取:通过串口端口(如 CS0)读取继电器的状态信息。
3. 状态处理:将串口数据转换为控制信号。
4. 动作执行:根据控制信号,触发继电器的动作动作。
5. 计时校准:在动作完成后,启动计时器,停止计时后停止动作。

6. 具体实现代码
c
void controlS Relays() {
    word pulseTimer = 0;
    bit pulseActive = 0;
   
    // 串口通信部分
    while ( ]; {// 需要定义串口通信的循环条件
   
      // 串口读取数据
      byte data = serialRead();
      
      // 状态转换
      if (data == 0) {// 不动作
            cmdReady = 1;
      } else if (data == 1) {// 动作
            cmdReady = 0;
      }
      
      // 线程校准
      pulseTimer = pulseTimer + 1;
      pulseActive = pulseActive & ~(1 > 8));
      
      // 线程停止
      if (cmdReady) {
            serialWrite(0, 0);
            serialWrite(0, 0);
            break;
      }
    }
   
    // 退出循环
    while ( ]; {// 需要定义循环的退出条件
      // 可以使用 break 或 continue 来退出循环
    }
}

7. 注意事项
串口通信的安全性:确保串口通信的端口开放和关闭符合安全规范。
计时器的准确性:确保计时器的计时周期和计时数符合要求。
状态转换的准确性:确保串口数据的转换与控制信号的一致性。

以上是国芯AI控制继电器的实现文档,希望对您有所帮助!

[本文内容由国芯人工智能辅助生成,仅供参考]

乘风飞扬 发表于 2025-5-20 11:06:23

这种问题最好提供相关的原理图,此外可先断开继电器电路,用示波器直接测量IO口电平试试。

DebugLab 发表于 2025-5-20 11:22:48

先测量IO是否有输出,再检查IO到继电器的电路,建议上传原理图

Ritchie 发表于 2025-5-20 14:06:43

这是其中的一路继电器端的原理图

Ritchie 发表于 2025-5-20 14:08:10

乘风飞扬 发表于 2025-5-20 11:06
这种问题最好提供相关的原理图,此外可先断开继电器电路,用示波器直接测量IO口电平试试。 ...

把后面的和IO口连接的电阻和发光二极管删卸掉了,IO一直是高电平没变化

Ritchie 发表于 2025-5-20 14:09:04

DebugLab 发表于 2025-5-20 11:22
先测量IO是否有输出,再检查IO到继电器的电路,建议上传原理图

把后面的和IO口连接的电阻和发光二极管删卸掉了,IO一直是高电平没变化

DebugLab 发表于 2025-5-20 14:20:42

注意11系列的PxMx与新型号的定义相反:

Ritchie 发表于 2025-5-20 14:54:07

DebugLab 发表于 2025-5-20 14:20
注意11系列的PxMx与新型号的定义相反:

可以看下最开始的帖子,我的代码就是这样写的。

DebugLab 发表于 2025-5-20 16:31:20

Ritchie 发表于 2025-5-20 14:54
可以看下最开始的帖子,我的代码就是这样写的。

直接操作IO呢
P33=0
P33=1
这样
页: [1] 2
查看完整版本: 11F02E通过IO口控制继电器,通过串口收到数据,继电器不动作,串口通信正常