找回密码
 立即注册
查看: 136|回复: 2

用stc32配合oled屏做了个剪线机,长度可调,可显示剪切次数

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:39
  • 最近打卡:2026-01-03 18:33:24
已绑定手机

7

主题

21

回帖

107

积分

注册会员

积分
107
发表于 2025-11-21 22:56:26 | 显示全部楼层 |阅读模式


用stc32配合oled屏做了个剪线机,长度可调,可显示剪切次数
下面是代码,欢迎指导改正。
  1. // 剪线机 时钟24MHz OLED显示(K1暂停+K2开始版)
  2. #include "stc.h"       // STC32G 寄存器定义(需适配24MHz)
  3. #include "oled.h"      // OLED驱动(128x64 I2C)
  4. #include "iic.h"
  5. #include <intrins.h>   
  6. // 宏定义(优化精度和保护阈值)
  7. #define DELAY_TIME     2000
  8. #define STEPS_PER_CM   56.5f    // 每厘米步数(根据实际电机校准)
  9. #define MIN_DISTANCE   10       // 最小剪线长度(cm)
  10. #define MAX_DISTANCE   100      // 最大剪线长度(cm)
  11. #define DEFAULT_DISTANCE 70     // 默认长度(cm)
  12. #define SERVO_OPEN     600      // 舵机打开(0.6ms,安全范围)
  13. #define SERVO_CUT      1500     // 舵机剪切(1.5ms,中间位置)
  14. #define PWM_CYCLE      20000    // 舵机PWM周期(20ms,标准舵机要求)
  15. #define PULSE_MIN      500      // 舵机最小脉冲(避免损坏)
  16. #define PULSE_MAX      2500     // 舵机最大脉冲
  17. #define KEY_DELAY      20       // 按键消抖延时(ms)
  18. #define STEP_PULSE_US  400      // 步进电机脉冲宽度(us)
  19. // 全局变量(新增pause暂停标志,优化状态管理)
  20. bit start = 0;                  // 启动标志(1=运行,0=待机)
  21. bit stop = 0;                   // 紧急停止标志(最高优先级,复位所有)
  22. bit pause = 0;                  // 暂停标志(1=暂停,0=正常)
  23. bit moving = 0;                 // 电机运行标志
  24. bit cut_flag = 0;               // 剪切触发标志(单次剪切完成)
  25. unsigned long steps_completed = 0;  // 已运行步数
  26. unsigned int target_distance = DEFAULT_DISTANCE;  // 目标剪线长度(cm)
  27. unsigned long total_steps = 0;  // 总需步数(target_distance * STEPS_PER_CM)
  28. unsigned int run_count = 0;     // 运行次数统计
  29. unsigned char PWM = 10;    // 初始脉宽1.5ms(对应90°),范围:10(0.5ms)~50(2.5ms)
  30. unsigned int count = 0;    // 计数器变量,用于计时中断周期
  31. // 引脚定义(明确按键功能)
  32. sbit K1      = P1^0;  // 暂停按键(仅运行中有效)
  33. sbit K2      = P1^1;  // 开始按键(待机/暂停状态有效)
  34. sbit K3      = P1^4;  // 增加长度按键(+5cm,仅待机/暂停有效)
  35. sbit K4      = P1^5;  // 减少长度按键(-5cm,仅待机/暂停有效)
  36. sbit SG_PWM   = P2^0;  // 舵机PWM输出引脚(定时器0控制)
  37. sbit DIR     = P2^3;  // 步进电机方向引脚(0=正转,1=反转)
  38. sbit STEP    = P2^4;  // 步进电机脉冲引脚
  39. sbit EN      = P2^5;  // 步进电机使能引脚(1=失能,0=使能)
  40. // 函数声明
  41. void sys_init(void);              // 系统初始化
  42. void key_scan(void);              // 按键扫描(带消抖)
  43. void key_process(unsigned char key);  // 按键功能处理
  44. void stepper_single_step(void);   // 步进电机单步驱动
  45. void run_stepper_motor(void);     // 电机运行+剪切逻辑
  46. void oled_update(void);           // OLED实时更新
  47. void delay_us(unsigned int us);   // 微秒延时(24MHz适配)
  48. void Timer0_Init(void);           // 定时器0初始化(补充声明)
  49. extern void delay_ms(unsigned int ms);  // 复用oled.c的毫秒延时
  50. /************************** 系统初始化 **************************/
  51. void sys_init(void) {
  52.     // 1. 时钟与端口配置
  53.     WTST = 0;        // CPU无等待周期
  54.     EAXFR = 1;       // 允许访问扩展寄存器
  55.     CKCON = 0x00;    // XRAM访问速度稳定
  56.     P0PU = 0xFF;     // 所有端口上拉(抗干扰)
  57.     P1PU = 0xFF;
  58.     P2PU = 0xFF;
  59.     P3PU = 0xFF;
  60.     // 2. 引脚模式配置
  61.     P1M0 = 0x00; P1M1 = 0x00;  // P1口(按键)准双向输入
  62.     P2M0 = 0x1B; P2M1 = 0x00;  // P2.0/P2.3/P2.4/P2.5推挽输出
  63.     P3M0 = 0x00; P3M1 = 0x00;  // 其他端口默认
  64.     // 3. 电机初始化(失能状态)
  65.     EN = 1;          // 电机失能
  66.     DIR = 0;         // 默认正转
  67.     STEP = 0;        // 脉冲初始低电平
  68.     // 4. 全局变量初始化
  69.     start = 0;
  70.     stop = 0;
  71.     pause = 0;
  72.     moving = 0;
  73.     cut_flag = 0;
  74.     steps_completed = 0;
  75.     target_distance = DEFAULT_DISTANCE;
  76.     total_steps = (unsigned long)(target_distance * STEPS_PER_CM);
  77.     run_count = 0;
  78.     // 5. 外设初始化
  79.                 Timer0_Init();  // 初始化定时器0(生成50us中断)
  80.     OLED_Init();     // OLED初始化
  81.     OLED_BuffClear();// 清空缓冲区
  82.     // 6. OLED初始显示(明确状态)
  83.     OLED_BuffShowString(0, 0, "Long: ", 0);
  84.     OLED_BuffShowNum(64, 0, target_distance, 3);  // 3位数字对齐
  85.     OLED_BuffShowString(96, 0, "cm", 0);
  86.     OLED_BuffShowString(0, 2, "No: ", 0);
  87.     OLED_BuffShowNum(64, 2, run_count, 3);
  88.     OLED_BuffShowString(96, 2, "Stop", 0);  // 初始待机状态
  89.     OLED_BuffShow();
  90. }
  91. /************************** 按键扫描(带消抖) **************************/
  92. void key_scan(void) {
  93.     static unsigned char key_state = 0;  // 0=空闲,1=消抖中,2=处理中
  94.     static unsigned char key_val = 0;    // 按键值(1=K1,2=K2,3=K3,4=K4)
  95.     static unsigned int key_timer = 0;   // 消抖计时
  96.     if (key_state == 0) {
  97.         // 检测按键按下
  98.         if (K1 == 0) key_val = 1;
  99.         else if (K2 == 0) key_val = 2;
  100.         else if (K3 == 0) key_val = 3;
  101.         else if (K4 == 0) key_val = 4;
  102.         else return;
  103.         key_state = 1;
  104.         key_timer = 0;
  105.     } else if (key_state == 1) {
  106.         // 消抖等待(20ms)
  107.         key_timer++;
  108.         delay_ms(1);
  109.         if (key_timer >= KEY_DELAY) {
  110.             // 确认按键仍按下
  111.             switch (key_val) {
  112.                 case 1: if (K1 == 0) key_state = 2; break;
  113.                 case 2: if (K2 == 0) key_state = 2; break;
  114.                 case 3: if (K3 == 0) key_state = 2; break;
  115.                 case 4: if (K4 == 0) key_state = 2; break;
  116.                 default: key_state = 0; break;
  117.             }
  118.         }
  119.     } else if (key_state == 2) {
  120.         // 执行按键功能
  121.         key_process(key_val);
  122.         // 等待按键释放(避免长按重复触发)
  123.         while (!(K1 && K2 && K3 && K4 )) delay_ms(1);
  124.         key_state = 0;
  125.     }
  126. }
  127. /************************** 按键功能处理(核心修改) **************************/
  128. void key_process(unsigned char key) {
  129.     switch (key) {
  130.         // 1. K1:暂停按键(仅运行中有效)
  131.         case 1:
  132.             if (start && !pause &&!stop  ) {  // 只有运行中才能暂停
  133.                 pause = 1;
  134.                 moving = 0;
  135.                 EN = 1;                  // 电机失能
  136.                 PWM = 10 ;  // 舵机复位
  137.                                                                 run_count= 0;  
  138.                                                          OLED_BuffClearLine(2);   // 清空状态行(第4行
  139.                OLED_BuffShowString(0, 2, "No: ", 0);
  140.                 OLED_BuffShowNum(64, 2, run_count, 0);  // 保留计数
  141.                 OLED_BuffShowString(96, 2, "Stop", 0);
  142.                 OLED_BuffShow();
  143.             }
  144.             break;
  145.         // 2. K2:开始按键(待机/暂停状态有效)
  146.         case 2:
  147.          
  148.             if (!start || pause) {  // 待机或暂停状态均可启动
  149.                 start = 1;
  150.                 pause = 0;  // 取消暂停
  151.                 cut_flag = 0;
  152.                 // 若未完成步数,继续运行;否则重置步数(新一次剪切)
  153.                 if (steps_completed >= total_steps) {
  154.                     steps_completed = 0;
  155.                 }
  156.                                                                 OLED_BuffClearLine(2);
  157.                 OLED_BuffShowString(0, 2, "No: ", 0);
  158.                 OLED_BuffShowNum(64, 2, run_count, 0);
  159.                 OLED_BuffShowString(96, 2, "Run  ", 0);  // 空格对齐,避免残留
  160.                 OLED_BuffShow();
  161.             }
  162.             break;
  163.         // 3. K3:增加长度(+5cm,仅待机/暂停有效)
  164.         case 3:
  165.             if (!start || pause) {  // 非运行状态才能调整
  166.                 if (target_distance < MAX_DISTANCE) {
  167.                     target_distance += 5;
  168.                     total_steps = (unsigned long)(target_distance * STEPS_PER_CM);
  169.                                                                           OLED_BuffClearLine(0);
  170.                                                                                 OLED_BuffShowString(0, 0, "Long: ", 0);
  171.                     OLED_BuffShowNum(64, 0, target_distance, 3);  // 强制3位显示
  172.                     OLED_BuffShowString(96, 0, "cm", 0);
  173.                     OLED_BuffShow();
  174.                 }
  175.             }
  176.             break;
  177.         // 4. K4:减少长度(-5cm,仅待机/暂停有效)
  178.         case 4:
  179.             if (!start || pause) {  // 非运行状态才能调整
  180.                 if (target_distance > MIN_DISTANCE) {
  181.                     target_distance -= 5;
  182.                     total_steps = (unsigned long)(target_distance * STEPS_PER_CM);
  183.                                                                                 OLED_BuffClearLine(0);
  184.                     OLED_BuffShowString(0, 0, "Long: ", 0);
  185.                     OLED_BuffShowNum(64, 0, target_distance, 3);  // 强制3位显示
  186.                     OLED_BuffShowString(96, 0, "cm", 0);
  187.                     OLED_BuffShow();
  188.                 }
  189.             }
  190.             break;
  191.     }
  192. }
  193. /************************** 步进电机单步驱动 **************************/
  194. void stepper_single_step(void) {
  195.     STEP = 1;
  196.     delay_us(STEP_PULSE_US);
  197.     STEP = 0;
  198.     delay_us(STEP_PULSE_US);
  199. }
  200. /************************** 电机运行+剪切逻辑(适配暂停功能) **************************/
  201. void run_stepper_motor(void) {
  202.     // 运行条件:启动=1、无紧急停止、无暂停、未完成剪切
  203.     if (start && !stop && !pause && !cut_flag && steps_completed < total_steps) {
  204.                        
  205.         EN = 0;          // 使能电机
  206.         moving = 1;      // 标记电机运行中
  207.         stepper_single_step();
  208.         steps_completed++;
  209.         // 步数完成→执行剪切
  210.         if (steps_completed >= total_steps) {
  211.             moving = 0;
  212.             EN = 1;                  // 电机失能
  213.             PWM = 30;             // 剪切
  214.             delay_ms(500);           // 保持500ms
  215.             PWM = 10;                                                  // 复位
  216.             delay_ms(500);           // 复位等待
  217.             run_count++;             // 计数+1
  218.                                                 OLED_BuffClearLine(2);   // 清空计数行(第2行)
  219.             OLED_BuffShowString(0, 2, "No: ", 0);
  220.             OLED_BuffShowNum(64, 2, run_count, 3);
  221.                                                 OLED_BuffShowString(96, 2, "Run  ", 0);
  222.             OLED_BuffShow();
  223.             OLED_BuffShow();
  224.             cut_flag = 0;            // 单次剪切完成
  225.                                                 delay_ms(500);           // 延时等待                                       
  226.                                                 steps_completed = 0;  // 重置步数,自动启动下一次
  227.         }
  228.     }
  229. }
  230. /**************************
  231. * 定时器0初始化:50us中断一次(24MHz 1T模式)
  232. **************************/
  233. void Timer0_Init(void) {
  234.     AUXR |= 0x80;        // 定时器0时钟1T模式(加速模式)
  235.     TMOD &= 0xF0;        // 定时器0工作模式:模式0(16位自动重装)
  236.     TL0 = 0x10;          // 50us中断初值:TL0=0x10(64336 = 0xFC10)
  237.     TH0 = 0xFC;          // 50us中断初值:TH0=0xFC
  238.     TF0 = 0;             // 清除定时器0溢出标志
  239.     TR0 = 1;             // 启动定时器0
  240.     ET0 = 1;             // 使能定时器0中断
  241.     EA = 1;              // 开启总中断
  242. }
  243. /**************************
  244. * 定时器0中断服务程序:生成PWM波形
  245. **************************/
  246. void Timer0_Isr(void) interrupt 1 {
  247.     count++;             // 每50us计数一次
  248.    
  249.     // 输出PWM高/低电平(脉宽由PWM变量控制)
  250.     SG_PWM = (count <= PWM) ? 1 : 0;
  251.    
  252.     // 20ms周期结束,计数器复位(400 * 50us = 20ms)
  253.     if (count >= 400) {
  254.         count = 0;       // 清零计数器,开始下一个周期
  255.     }
  256. }
  257. /************************** 延时函数 **************************/
  258. void delay_us(unsigned int us) {
  259.     unsigned int i;
  260.     for (i = 0; i < us * 3; i++) {  // 24MHz下≈1us
  261.         _nop_(); _nop_(); _nop_(); _nop_();
  262.     }
  263. }
  264. /************************** 主函数 **************************/
  265. void main(void) {
  266.     sys_init();
  267.     while (1) {
  268.         key_scan();          // 按键扫描
  269.         run_stepper_motor(); // 核心控制逻辑
  270.     }
  271. }
复制代码

1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:690
  • 最近打卡:2026-03-17 00:41:35
已绑定手机

49

主题

2638

回帖

2860

积分

荣誉版主

积分
2860
发表于 2025-11-22 12:26:32 | 显示全部楼层
原理上没问题,实测舵机的扭矩够剪线吗?
~~~
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:39
  • 最近打卡:2026-01-03 18:33:24
已绑定手机

7

主题

21

回帖

107

积分

注册会员

积分
107
发表于 2025-11-22 22:48:02 | 显示全部楼层
晓*** 发表于 2025-11-22 12:26
原理上没问题,实测舵机的扭矩够剪线吗?

0.3的试过可以,有点小。大舵机太贵了。不如两个步进
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-3-17 17:34 , Processed in 0.355124 second(s), 55 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表