您现在所在的是:

无所不谈

回帖:0个,阅读:8 [上一页] [1] [下一页]
3295
czhaii
文章数:689
年度积分:937
历史总积分:3295
注册时间:2016/3/13
发站内信
发表于:2026/7/29 11:30:37
#0楼
最近STC官方BBS右下角出现一个弹窗
Ai助手上线
让大家来测试
于是先让写一个RA8835控制的320240程序
再写一个简单的自动运行机器程序
嗖嗖嗖一分钟不到写出来了

然后让写一个增量式编码器正反转计数程序
刚开始简单的还行
然后问我

1. 您使用的是哪一款具体的STC单片机型号?

   例如:STC8H8K64U、STC8G1K08A、STC8A8K64D4、STC32G12K128、STC15W4K32S4 等
   不同型号的编码器接口(正交解码/外部中断/定时器捕获)和I2C硬件模块差异较大

2. 编码器的信号输出方式?

   AB相正交脉冲(最常见,带方向)→ 可用高级PWM的正交编码器模式或外部中断+定时器捕获
   单脉冲+方向电平(PULSE+DIR)→ 可用外部中断计数+IO判断方向
   仅单脉冲(无方向)→ 仅计数

3. 您希望OLED上显示什么内容?

   例如:当前位置值、转速(RPM)、方向(CW/CCW)、脉冲计数值等

4. 编码器每转多少脉冲(PPR)?

   例如 100、400、1000 等,用于计算转速

请先告诉我以上信息,我马上为您编写一份可直接编译运行的完整代码!


我答:1任意一款单片机2AB相正交脉冲3当前位置值、转速(RPM)、方向(CW/CCW)、脉冲计数值等4每转1000脉冲

提交以后开始刷刷刷刷出代码
出了几秒钟以后突然全部清空

说 抱歉,服务暂时不可用。
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////


选择一块STC单片机 写一个增量式编码器正反转计数程序
AI

好的,根据已有信息,我来整理一下。从管脚图可以看到,PWM1P(P1.0)是PWM通道1的捕获输入/输出正极,PWM2P(P5.4/P2.2等)是通道2的捕获输入/输出正极。在编码器模式下,TI1对应通道1输入(PWM1P),TI2对应通道2输入(PWM2P)。

现在我来编写完整的程序。我选择 STC8H8K64U 这款芯片,因为它资源丰富、支持高级PWM正交编码器模式,且带有USB接口方便调试。

让我先确认一下PWM1P和PWM2P的默认引脚位置。

从管脚图可以看到:

   PWM1P(通道1捕获输入)默认在 P1.0
   PWM2P(通道2捕获输入)默认在 P5.4(LQFP64的18脚)

不过为了更方便使用,我也可以使用P2.2作为PWM2P_2。让我用默认引脚P1.0和P5.4。

现在编写完整的程序:
方案选择

我选择 STC8H8K64U 系列单片机,理由如下:

   ? 内置高级PWM定时器,硬件支持正交编码器接口模式
   ? 硬件自动完成正反转判断和计数,无需软件干预
   ? 资源丰富(64KB Flash、8KB SRAM),带USB接口方便调试
   ? 价格适中,供货稳定

硬件连接
编码器信号 STC8H8K64U引脚 说明
A相(CH A) P1.0(PWM1P) 高级PWM通道1输入(TI1)
B相(CH B) P5.4(PWM2P) 高级PWM通道2输入(TI2)
Z相(零位,可选) 任意I/O口(如P3.2/INT0) 外部中断,用于归零
完整程序代码

/*
* ============================================================
* 文件名: encoder_counter.c
* 芯片型号: STC8H8K64U(LQFP64/QFN64)
* 功能描述: 增量式编码器正反转计数程序
*           使用高级PWM的硬件正交编码器接口模式,
*           硬件自动完成4倍频计数和方向判断。
* 硬件连接:
*   - 编码器A相 -> P1.0 (PWM1P/TI1)
*   - 编码器B相 -> P5.4 (PWM2P/TI2)
*   - 串口1(TxD/P3.1) -> 输出计数值到串口助手(115200,8n1)
* 时钟: 内部IRC 24MHz(使用STC-ISP下载时设置)
* 编译环境: Keil C51
* ============================================================
*/

#include "STC8H.h"

/* 使用内部IRC 24MHz,无需外部晶振 */

/* 全局变量 */
volatile signed long encoder_count;      // 编码器当前位置计数值(有符号)
volatile unsigned char encoder_dir;      // 当前方向:0=正转(向上计数),1=反转(向下计数)
volatile unsigned char update_flag;      // 更新标志,主循环轮询

/* 定时器2用于1ms定时,作为周期性读取编码器值的时基 */
volatile unsigned int timer2_count;

/* 函数声明 */
void System_Init(void);
void PWM_Encoder_Init(void);
void Timer2_Init(void);
void UART1_Init(void);
void UART1_SendString(unsigned char *str);
void UART1_SendLong(signed long val);

/* 主函数 */
void main(void)
{
   unsigned char buf[32];
   
   System_Init();          // 系统初始化
   PWM_Encoder_Init();     // 高级PWM编码器模式初始化
   Timer2_Init();          // 定时器2初始化(1ms时基)
   UART1_Init();           // 串口1初始化(115200bps)
   
   EA = 1;                 // 开启总中断
   
   UART1_SendString("STC8H8K64U 增量式编码器计数程序启动\r\n");
   UART1_SendString("编码器A相 -> P1.0, B相 -> P5.4\r\n");
   
   while(1)
   {
       /* 每100ms读取一次编码器值并输出 */
       if(update_flag)
       {
           update_flag = 0;
           
           /* 读取当前编码器计数值(16位有符号数) */
           /* PWMA_CNTR是16位计数器,编码器模式下自动在0~ARR之间计数 */
           /* 方向由硬件自动判断,DIR位指示方向 */
           
           /* 读取当前计数器值 */
           encoder_count = (signed int)PWMA_CNTR;
           
           /* 读取方向位:PWMA_CR1的bit4是DIR */
           if(PWMA_CR1 & 0x10)
               encoder_dir = 1;    // 反转(向下计数)
           else
               encoder_dir = 0;    // 正转(向上计数)
           
           /* 通过串口输出 */
           UART1_SendString("Pos: ");
           UART1_SendLong(encoder_count);
           if(encoder_dir)
               UART1_SendString(" DIR:REV\r\n");
           else
               UART1_SendString(" DIR:FWD\r\n");
       }
   }
}

/*============================================================
* 系统初始化
* 设置系统时钟为24MHz,端口模式等
*============================================================*/
void System_Init(void)
{
   /* 设置内部IRC频率为24MHz(需在STC-ISP下载时选择24MHz) */
   /* 如果下载时已设置好,此处无需额外操作 */
   
   /* 设置P1.0和P5.4为高阻输入模式(编码器信号输入) */
   P1M0 &= ~0x01;      // P1.0: M0=0
   P1M1 |= 0x01;       // P1.0: M1=1 -> 高阻输入
   
   P5M0 &= ~0x10;      // P5.4: M0=0
   P5M1 |= 0x10;       // P5.4: M1=1 -> 高阻输入
   
   /* P3.1(TxD)设置为推挽输出 */
   P3M0 |= 0x02;       // P3.1: M0=1
   P3M1 &= ~0x02;      // P3.1: M1=0 -> 推挽输出
}

/*============================================================
* 高级PWM编码器模式初始化
* 配置PWMA为编码器接口模式,TI1=P1.0(PWM1P), TI2=P5.4(PWM2P)
* 编码器模式3:TI1和TI2双边沿计数(4倍频)
*============================================================*/
void PWM_Encoder_Init(void)
{
   /* 使能访问XFR(扩展特殊功能寄存器) */
   P_SW2 |= 0x80;
   
   /*----------------------------------------------------------
    * 步骤1:配置捕获/比较通道1和2的输入映射
    * PWMA_CCMR1: CC1S[1:0]=01 -> IC1FP1映射到TI1
    * PWMA_CCMR2: CC2S[1:0]=01 -> IC2FP2映射到TI2
    *----------------------------------------------------------*/
   PWMA_CCMR1 = (PWMA_CCMR1 & ~0x03) | 0x01;   // CC1S=01
   PWMA_CCMR2 = (PWMA_CCMR2 & ~0x03) | 0x01;   // CC2S=01
   
   /*----------------------------------------------------------
    * 步骤2:配置输入极性
    * PWMA_CCER1: CC1P=0 (不反相), CC2P=0 (不反相)
    *----------------------------------------------------------*/
   PWMA_CCER1 = 0x00;   // CC1P=0, CC2P=0
   
   /*----------------------------------------------------------
    * 步骤3:配置从模式控制寄存器为编码器模式3
    * PWMA_SMCR: SMS[2:0]=011 -> 编码器模式3
    * 在TI1和TI2的上升沿和下降沿都计数(4倍频)
    *----------------------------------------------------------*/
   PWMA_SMCR = (PWMA_SMCR & ~0x07) | 0x03;     // SMS=011
   
   /*----------------------------------------------------------
    * 步骤4:设置自动重装载值(ARR)
    * 编码器模式下,计数器在0~ARR之间循环计数
    * 设置为最大值0xFFFF,获得最大计数范围
    * 注意:编码器模式下ARR决定计数范围,不决定频率
    *----------------------------------------------------------*/
   PWMA_ARR = 0xFFFF;   // 16位最大计数范围
   
   /*----------------------------------------------------------
    * 步骤5:使能计数器
    * PWMA_CR1: CEN=1 启动计数器
    *----------------------------------------------------------*/
   PWMA_CR1 |= 0x01;    // CEN=1
   
   /* 初始化计数值 */
   encoder_count = 0;
   encoder_dir = 0;
}

/*============================================================
* 定时器2初始化
* 定时器2作为1ms时基,用于周期性读取编码器
* 时钟源=24MHz, 12T模式, 重载值=24000000/12/1000=2000
*============================================================*/
void Timer2_Init(void)
{
   /* 定时器2是16位自动重装载定时器 */
   /* T2H/T2L = 65536 - 24000000/12/1000 = 65536 - 2000 = 63536 = 0xF830 */
   T2L = 0x30;          // 低字节
   T2H = 0xF8;          // 高字节
   
   /* 使能定时器2中断 */
   IE2 |= 0x04;         // ET2=1
   
   /* 启动定时器2 */
   AUXR |= 0x10;        // T2R=1, 且T2x12=0(12T模式)
}

/*============================================================
* 串口1初始化
* 波特率115200, 8位数据, 1位停止位, 无校验
* 使用定时器1作为波特率发生器
* 24MHz, 8位自动重载, 12T模式
* 重载值 = 256 - 24000000/12/32/115200 = 256 - 54 = 202 = 0xCA
*============================================================*/
void UART1_Init(void)
{
   /* 设置定时器1为8位自动重装载模式 */
   TMOD = (TMOD & ~0xF0) | 0x20;   // T1: 模式2(8位自动重载)
   
   /* 设置重载值 */
   TH1 = 0xCA;          // 波特率115200 @24MHz
   TL1 = 0xCA;
   
   /* 启动定时器1 */
   TR1 = 1;
   
   /* 设置串口1模式1(8位UART), 使能接收 */
   SCON = 0x50;         // SM0=0, SM1=1, REN=1
   
   /* 使用定时器1作为波特率发生器 */
   AUXR &= ~0x01;       // S1ST2=0, 使用T1
   AUXR |= 0x40;        // T1x12=1 (1T模式, 实际上面计算已按12T)
   /* 更正:上面按12T计算,这里应设T1x12=0 */
   AUXR &= ~0x40;       // T1x12=0 (12T模式)
   
   /* 使能串口1中断 */
   ES = 1;
}

/*============================================================
* 串口发送字符串
*============================================================*/
void UART1_SendString(unsigned char *str)
{
   while(*str)
   {
       SBUF = *str++;
       while(TI == 0);  // 等待发送完成
       TI = 0;
   }
}

/*============================================================
* 串口发送有符号长整数(十进制)
*============================================================*/
void UART1_SendLong(signed long val)
{
   unsigned char buf[12];
   unsigned char i = 0;
   unsigned char j;
   unsigned char negative = 0;
   
   if(val < 0)
   {
       negative = 1;
       val = -val;
   }
   
   /* 转换为十进制字符串(倒序) */
   do {
       buf[i++] = (unsigned char)(val % 10) + '0';
       val /= 10;
   } while(val > 0);
   
   if(negative)
       buf[i++] = '-';
   
   /* 倒序输出 */
   for(j = i; j > 0; j--)
   {
       SBUF = buf[j-1];
       while(TI == 0);
       TI = 0;
   }
   
   /* 发送结束 */
   SBUF = ' ';
   while(TI == 0);
   TI = 0;
}

/*============================================================
* 定时器2中断服务程序
* 每1ms中断一次,累计到100ms设置更新标志
*============================================================*/
void Timer2_ISR(void) interrupt 12
{
   /* 清除定时器2中断标志 */
   IE2 &= ~0x04;        // 软件清除TF2
   
   timer2_count++;
   if(timer2_count >= 100)     // 100ms
   {
       timer2_count = 0;
       update_flag = 1;
   }
}

/*============================================================
* 串口1中断服务程序
* 本示例中未使用接收功能,仅保留框架
*============================================================*/
void UART1_ISR(void) interrupt 4
{
   if(RI)
   {
       RI = 0;          // 清除接收中断标志
       /* 可在此处添加接收处理 */
   }
   if(TI)
   {
       TI = 0;          // 清除发送中断标志(已在查询方式中处理)
   }
}

程序说明
1. 编码器工作原理

增量式编码器输出两路相位差90°的方波信号(A相和B相):

   正转:A相领先B相90°
   反转:B相领先A相90°

STC8H系列的高级PWM定时器内置硬件正交编码器接口,可以自动:

   在A相和B相的上升沿和下降沿都计数(4倍频,分辨率×4)
   根据相位关系自动判断方向(DIR位)
   计数器自动向上/向下计数

2. 关键配置说明
配置项 寄存器 值 说明
CC1S PWMA_CCMR1[1:0] 01 IC1FP1映射到TI1(PWM1P)
CC2S PWMA_CCMR2[1:0] 01 IC2FP2映射到TI2(PWM2P)
CC1P/CC2P PWMA_CCER1 0 输入不反相
SMS PWMA_SMCR[2:0] 011 编码器模式3(双边沿计数)
CEN PWMA_CR1[0] 1 使能计数器
ARR PWMA_ARR 0xFFFF 最大计数范围65535
3. 引脚分配
引脚 功能 说明
P1.0 PWM1P (TI1) 编码器A相输入
P5.4 PWM2P (TI2) 编码器B相输入
P3.1 TxD 串口输出(115200bps)
4. 使用步骤

   在 STC-ISP下载软件 中:
       选择芯片型号:STC8H8K64U
       设置内部IRC频率:24MHz
       打开程序文件,下载到芯片

   硬件连接:

   编码器A相 ----> P1.0
   编码器B相 ----> P5.4
   编码器VCC ----> 3.3V/5V(根据编码器规格)
   编码器GND ----> GND

   打开串口助手(115200, 8N1),旋转编码器即可看到:

   Pos: 1234 DIR:FWD
   Pos: 1240 DIR:FWD
   Pos: 1238 DIR:REV

5. 扩展功能建议

   Z相归零:可将编码器Z相(零位信号)接到外部中断引脚(如P3.2/INT0),在中断中复位计数器
   速度测量:使用另一个定时器测量两次编码器读数的时间间隔,计算转速
   增加滤波:可通过PWMA_CCMR1/2的ICF[3:0]位配置输入滤波器,增强抗干扰能力

如果您需要其他封装(如TSSOP20、LQFP32等)或不同型号的适配版本,请告诉我具体的芯片型号和封装,我可以为您调整引脚配置。

?? 搜索 "选择一块STC单片机 写一个增量式编码器正反转计数程序"

?? 相关论坛讨论

   STC8H8K64U有没有用开关控制电机正反转,根据编码器计数判电机受阻后反转,PWM频率宽
   PWM编码器计数溢出中断怎么用?
   电机小白咨询

?? 查找用时 38.7s | 总回答用时 72.3s
?

将数据显示到0.96英寸IIC OLED上
AI

好的,我已经查到了STC各主流系列(STC8H、STC8G、STC8A8K64D4等)的硬件I2C模块寄存器配置方法。不过,在给出完整代码之前,我需要您先确认一下:

请问您使用的是哪一款具体的STC单片机型号?(例如:STC8H8K64U、STC8G1K08A、STC8A8K64D4、STC15W4K32S4、STC32G12K128 等)

不同型号的差异主要在于:

   I2C硬件模块:STC8系列/STC32系列有硬件I2C控制器,而STC15系列没有独立I2C硬件,需要用GPIO模拟I2C时序
   主频:影响I2C速率配置和延时参数
   I/O口:I2C引脚可切换的端口不同

请告诉我您的具体型号,我马上为您编写一份可直接编译运行的OLED驱动代码!

?? 搜索 "将数据显示到0.96英寸IIC OLED上"

?? 相关论坛讨论

   STC32测试SPI接口0.96英寸 OLED显示
   STC32G + IIC 0.96寸 Oled 显示 米老鼠、懒羊羊 图片
   I2C驱动0.96寸 OLED屏幕, STC32位8051

?? 查找用时 7.6s | 总回答用时 12.1s
?

将增量式脉冲编码器测量数据显示到0.96英寸IIC OLED上
AI

好的,这是一个非常实用的组合需求——用STC单片机读取增量式编码器,然后将数据(如位置、速度、方向)显示在0.96寸IIC OLED(SSD1306)上。

不过,在给出完整代码之前,我需要先确认几个关键信息,以确保代码能直接为您所用:

1. 您使用的是哪一款具体的STC单片机型号?

   例如:STC8H8K64U、STC8G1K08A、STC8A8K64D4、STC32G12K128、STC15W4K32S4 等
   不同型号的编码器接口(正交解码/外部中断/定时器捕获)和I2C硬件模块差异较大

2. 编码器的信号输出方式?

   AB相正交脉冲(最常见,带方向)→ 可用高级PWM的正交编码器模式或外部中断+定时器捕获
   单脉冲+方向电平(PULSE+DIR)→ 可用外部中断计数+IO判断方向
   仅单脉冲(无方向)→ 仅计数

3. 您希望OLED上显示什么内容?

   例如:当前位置值、转速(RPM)、方向(CW/CCW)、脉冲计数值等

4. 编码器每转多少脉冲(PPR)?

   例如 100、400、1000 等,用于计算转速

请先告诉我以上信息,我马上为您编写一份可直接编译运行的完整代码!

?? 搜索 "增量式编码器 I2C OLED 数据显示"

?? 相关论坛讨论

   STC32测试SPI接口0.96英寸 OLED显示
   2023电赛E题国二作品开源(文末附核心代码)
   国二,使用 STC32完成E题获得国二!

?? 查找用时 0.7s | 总回答用时 5.6s
?

1任意一款单片机2AB相正交脉冲3当前位置值、转速(RPM)、方向(CW/CCW)、脉冲计数值等4每转1000脉冲
AI

抱歉,服务暂时不可用。

关于我们 | 联系我们 | 广告服务 | 本站动态 | 友情链接 | 法律声明 | 非法和不良信息举报

工控网客服热线:0755-86369299
版权所有 工控网 Copyright©2026 Gkong.com, All Rights Reserved

62.4004