迪文科技论坛

 找回密码
 立即注册
搜索
查看: 170|回复: 0

【2022.8.20获奖项目】智能柜设计

[复制链接]

567

主题

167

回帖

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
11979
发表于 2024-1-10 19:34:05 | 显示全部楼层 |阅读模式
最近帮客户做了一款针对实验柜的舵机控制系统,本着完美主义,我在这里将用T5L屏设计一款高端大气时尚的智能柜管理系统。
(资料陆续更新,欢迎大家提出批评建议)
(dgus工程所用图片均来自于网络,仅供各位朋友交流参考,请勿商用)






首先说一下本智能柜的优势:
1、兼容性:
(1)液晶屏(操作面包)兼容性:在设计上采用了T5L标准屏作为主控,直接驱动串行总线舵机,传感器汇总到辅助控制器(如STC系列单片机,再将数据通过串口4发送给液晶屏,在实际开发过程中,只需要根据采用的液晶屏的分辨率改变DGUS工程就行。
(2)舵机兼容性:采用飞特的STS系列串行总线舵机作为驱动,这类舵机的力矩涵盖了4.5KG到40KG,且它们的协议通用
2、安全性:串行总线舵机具有电流、力矩、温度、电压保护功能,其使用安全性要高于常规的电机。
3、可拓展性:串行总线舵机,理论上来说,一个串口支持同时控制254个舵机,即一块液晶屏作为主控,可以带动254个舵机。



演示视频:链接: https://pan.baidu.com/s/19_-gfqtCd4SaAHN9-SsLMQ?pwd=4967 提取码: 4967 复制这段内容后打开百度网盘手机App,操作更方便哦

关于演示视频的几点说明:
1. 视频中采用的舵机为飞特SCS115型与SCS40两种型号的舵机,电源为24V开关电源,经降压至8-9V接入舵机
2. DGUS工程为800*480的,但我的80480的屏摔坏了,所以用的7寸1024*600的液晶屏
3. 由于论坛里有大神已经做了时间更新与flash操作的代码(迪文温控器代码),所以我就不做演示
4. 关于舵机动作顺序,开门:门栓舵机动作完成,开门舵机再动作;关门:开门舵机动作完成,然后门栓舵机再动作


如下图所示,为本文设计的智能柜的框架,迪文屏作为主控制器,通过串口2直接输出指令控制串行总线舵机,串口4与辅助控制器连接,用于拓展传感器,例如用于化学实验柜,可以拓展用以检测温度、气体、火焰检测等传感器。灯光系统用于智能柜内部照明使用,采用行程开关与光耦传感器共同控制,即在照明不良、柜门打开时,点亮照明灯光,电路见下文。


为了防止停电时,智能柜门处于失控状态,本设计采用了双舵机的设计,即开门舵机负责柜门的开关动作,门闩舵机负责门闩动作,停电后,由于门闩的存在,即使开门舵机卸力,智能柜也依然处于上锁状态,当然,如果用户觉得双舵机的成本太高,可以选择不加门闩舵机,对本设计的系统运行并不产生影响。机械结构如图所示:




接下来说明一下本设计的程序框架,程序是C51语言,在液晶屏中运行:



电路原理图分为三部分:主电路板(舵机驱动电路+辅助控制器+接口)、降压电路、灯光电路(安装在柜子里边)。




我在这里使用STM32F103RCT6作为辅助控制器,单片机的串口1与液晶屏的串口4相连接,液晶屏串口2直接驱动舵机,同时设计有一路输入,一路输出,用于紧急情况。





辅助控制器与传感器使用的电压多为5V,而舵机的电压直接与舵机型号相关,例如SCS115型的电压为7-8V,因此本设计采用了LM2596S-5.0输出5V电压,LM2596S-ADJ可调输出7.5V电压用于舵机,不同的电压,调节电阻R_ADJ的阻值即可。

由于使用的降压芯片为LM2596S,支持最大输入电压40V。





这里采用了光耦电阻检测亮度,行程开关与柜门相接,当柜门打开时,行程开关导通,如果光线太暗,小灯泡就可以点亮。
降压板与驱动板安装在如下图所示的小盒子里(3D图纸见附件),底层为降压板,上层为主电路板。





1.温湿度检测与刷新,时间更新(由辅助控制器驱动AHT21,将温湿度数据写入迪文屏)
  1. /*****************温湿度更新**********************/
  2. void dwin_Tempe_humi_update( void)
  3. {
  4.         uint8_t  Tempe_humi_date[20];  //发送给液晶屏的指令
  5.         AHT20_Read_CTdata(CT_data);  //读取温度和湿度
  6.         
  7.         Tempe_humi_date[0]=0x5A;
  8.         Tempe_humi_date[1]=0xA5;
  9.         Tempe_humi_date[2]=0x07;
  10.         Tempe_humi_date[3]=0x82;
  11.         Tempe_humi_date[4]=(ADDR_TEMP_HUMI>>8)&0xff;
  12.         Tempe_humi_date[5]=ADDR_TEMP_HUMI&0xff;
  13.         Tempe_humi_date[6]=((CT_data[1] *200*10/1024/1024-500)>>8)&0xff;
  14.         Tempe_humi_date[7]=((CT_data[1] *200*10/1024/1024-500))&0xff;//计算得到温度值(放大了10倍,如果t1=245,表示现在温度为24.5℃)
  15.         Tempe_humi_date[8]=((CT_data[0]*1000/1024/1024)>>8)&0xff;
  16.         Tempe_humi_date[9]=((CT_data[0]*1000/1024/1024))&0xff;  //计算得到湿度值(放大了10倍,如果c1=523,表示现在湿度为52.3%)
  17.         Usart_SendString( USART_DWIN,Tempe_humi_date,10);

  18. }

  19. /*****************时间更新**********************/

  20. uint8_t  DGUS_RTC_date[40];  
  21. void dwin_time_update( u32 time_value)
  22. {
  23.         struct rtc_time time;
  24.         unsigned int days,hour_min_sec;
  25.         unsigned int i;
  26.         
  27.         days = time_value / 86400;//一天有86400秒
  28.         hour_min_sec = time_value % 86400;//一天有86400秒
  29.         
  30.         time.hour = hour_min_sec / 3600;//一小时有3600秒
  31.         time.mintute =( hour_min_sec % 3600 ) / 60;//一分钟有60秒
  32.         time.second =( hour_min_sec % 3600 ) % 60;
  33.         
  34.         //年份判断,从1970年开始
  35.         for ( i=1970;days>=days_in_years(i);i++)
  36.         {
  37.                 days-=days_in_years(i);
  38.         }
  39.         time.year=i;
  40.         //判断月份
  41.         if (leapyear(i))
  42.                 days_in_month[2]=29;
  43.         else
  44.                 days_in_month[2]=28;
  45.                 for ( i=1;days>=days_in_month;i++)
  46.         {
  47.                 days-=days_in_month;
  48.         }
  49.         time.month = i;
  50.         //日期计算
  51.         time.day = days + 1 ;
  52.         
  53.         time.week=RTC_Get_Week(time.year,time.month, time.day);

  54.         DGUS_RTC_date[0]=0x5A;
  55.         DGUS_RTC_date[1]=0xA5;
  56.         DGUS_RTC_date[2]=0x18;
  57.         DGUS_RTC_date[3]=0x82;
  58.         DGUS_RTC_date[4]=(ADDR_RTC_TIME>>8)&0xff;
  59.         DGUS_RTC_date[5]=ADDR_RTC_TIME&0xff;
  60.         DGUS_RTC_date[6]=0x00;
  61.         DGUS_RTC_date[7]=time.hour;//时
  62.         DGUS_RTC_date[8]=0x00;
  63.         DGUS_RTC_date[9]=time.mintute;//分
  64.         DGUS_RTC_date[10]=00;
  65.         DGUS_RTC_date[11]=time.second;//秒
  66.         DGUS_RTC_date[12]=(time.year>>8)&0xff;//年
  67.         DGUS_RTC_date[13]=time.year&0xff;//年
  68.         DGUS_RTC_date[14]=00;
  69.         DGUS_RTC_date[15]=time.month;//月
  70.         DGUS_RTC_date[16]=00;
  71.         DGUS_RTC_date[17]=time.day;//日
  72.         
  73.         DGUS_RTC_date[18]=ascii_8hex[2*weeks(time.week)+0];//(time.week>>8)&0xff;//ascii_8hex[];//
  74.         DGUS_RTC_date[19]=ascii_8hex[2*weeks(time.week)+1];// time.week&0xff;//当前星期
  75.         

  76.         Usart_SendString( USART_DWIN,DGUS_RTC_date,26);
  77.         

  78. }
  79. //星期运算


  80. uint16_t weeks(int weekday)
  81. {
  82. //        uint16_t asic_2_h;
  83.         if(weekday>6)
  84.                 weekday-=7;

  85.         return weekday;
  86. }

复制代码
(上传空间有限,需要详细资料的请邮箱联系1462818330@qq.com





本节主要是简单说一下飞特舵机指令协议,供大家做个参考。
飞特舵机STS系列采用TTL通信,指令格式为8-N-1,波特率默认1000000,可以更改为1000000,500000,250000,128000,115200,76800,57600,38400

1.指令

     字头   ID号    数据长度   指令       参数               校验和

     0XFF   0XFF ID  Length   Instruction   Parameter1 ...Parameter N  Check Sum

字头:连续收到两个 0XFF ,表示有数据包到达。
ID: 每个舵机都有一个 ID 号。 ID 号范围 0~253,转换为十六进制 0X00~0XFD。
广播 ID: ID 号 254 为广播 ID,若控制器发出的 ID 号为 254(0XFE),所有的舵机均接收指令,除 PING 指令外其它指令均不返回应答信息(多个舵机连接在总线上不能使用广播 PING指令)。
数据长度:等于待发送的参数长度 N 加上 2,即“N+2”。
参数:除指令外需要补充的控制信息,参数最大支持双字节参数表示一个内存值,字节顺序参考舵机使用手册(不同型号舵机字节顺序不一样)。
校验和:校验和 Check Sum,计算方法如下:Check Sum = ~ (ID + Length + Instruction + Parameter1 + ... Parameter N)
若括号内的计算和超出 255,则取最低的一个字节,“~”表示取反。

例如,控制舵机转到1500位置,则指令为FF FF 01 0A 03 29 32 E8 03 00 00 E8 03 C0 ,该指令控制舵机位置与转动速度、加速度

2.应答

    字头      ID  数据长度     当前状态 参数                校验和

    0XFF    0XFF ID  Length     ERROR   Parameter1 ...Parameter N  Check Sum

返回的应答包包含舵机的当前状态 ERROR,若舵机当前工作状态不正常,会通过这个字节反映出来,若 ERROR 为 0,则舵机无报错信息。
若指令是读指令 READ DATA,则 Parameter1 ...Parameter N 是读取的信息。
详细舵机指令说明,大家可以自行查找官网。

主要功能程序说明:2.舵机内存表宏定义(节选)

#define SCSCL_ID 5
#define SCSCL_BAUD_RATE 6
#define SCSCL_RETURN_DELAY_TIME 7
#define SCSCL_RETURN_LEVEL 8
#define SCSCL_MIN_ANGLE_LIMIT_L 9
#define SCSCL_MIN_ANGLE_LIMIT_H 10
#define SCSCL_MAX_ANGLE_LIMIT_L 11
#define SCSCL_MAX_ANGLE_LIMIT_H 12
#define SCSCL_LIMIT_TEMPERATURE 13
#define SCSCL_MAX_LIMIT_VOLTAGE 14
#define SCSCL_MIN_LIMIT_VOLTAGE 15
#define SCSCL_MAX_TORQUE_L 16
#define SCSCL_MAX_TORQUE_H 17
#define SCSCL_ALARM_LED 19
#define SCSCL_ALARM_SHUTDOWN 20
#define SCSCL_COMPLIANCE_P 21
#define SCSCL_COMPLIANCE_D 22
#define SCSCL_COMPLIANCE_I 23
#define SCSCL_PUNCH_L 24
#define SCSCL_PUNCH_H 25
#define SCSCL_CW_DEAD 26
#define SCSCL_CCW_DEAD 27
#define SCSCL_PROTECT_TORQUE 37
#define SCSCL_PROTECT_TIME 38
#define SCSCL_OVLOAD_TORQUE 39
#define SCSCL_TORQUE_ENABLE 40
#define SCSCL_GOAL_POSITION_L 42
#define SCSCL_GOAL_POSITION_H 43
#define SCSCL_GOAL_TIME_L 44
#define SCSCL_GOAL_TIME_H 45
#define SCSCL_GOAL_SPEED_L 46
#define SCSCL_GOAL_SPEED_H 47
#define SCSCL_LOCK 48


3.舵机服务子程序(其他子程序,由于篇幅有限,这里就不写)
  1. int writePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed, uint8_t Fun)
  2. {
  3.         uint8_t buf[6];
  4.         flushSCS();//清空缓冲区

  5.         u16_to_u8(buf+0, buf+1, Position);
  6.         u16_to_u8(buf+2, buf+3, Time);
  7.         u16_to_u8(buf+4, buf+5, Speed);
  8.         writeBuf(ID, SCSCL_GOAL_POSITION_L, buf, 6, Fun);
  9.         return Ack(ID);
  10. }

  11. //写位置指令
  12. //舵机ID,Position位置,运行时间Time,速度Speed
  13. int WritePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed)
  14. {
  15.         return writePos(ID, Position, Time, Speed, INST_WRITE);
  16. }

  17. //异步写位置指令
  18. //舵机ID,Position位置,运行时间Time,速度Speed
  19. int RegWritePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed)
  20. {
  21.         return writePos(ID, Position, Time, Speed, INST_REG_WRITE);
  22. }

  23. void RegWriteAction(void)
  24. {
  25.         writeBuf(0xfe, 0, NULL, 0, INST_ACTION);
  26. }

  27. //写位置指令
  28. //舵机ID[]数组,IDN数组长度,Position位置,运行时间Time,速度Speed
  29. void SyncWritePos(uint8_t ID[], uint8_t IDN, uint16_t Position, uint16_t Time, uint16_t Speed)
  30. {
  31.         uint8_t buf[6];

  32.         u16_to_u8(buf+0, buf+1, Position);
  33.         u16_to_u8(buf+2, buf+3, 0);
  34.         u16_to_u8(buf+4, buf+5, Speed);
  35.         snycWrite(ID, IDN, SCSCL_GOAL_POSITION_L, buf, 6);
  36. }

  37. //读位置,超时返回-1
  38. int ReadPos(uint8_t ID)
  39. {
  40.         return readWord(ID, SCSCL_PRESENT_POSITION_L);
  41. }

  42. //速度控制模式
  43. int WriteSpe(uint8_t ID, int16_t Speed)
  44. {
  45.         if(Speed<0){
  46.                 Speed = -Speed;
  47.                 Speed |= (1<<10);
  48.         }
  49.         return writeWord(ID, SCSCL_GOAL_TIME_L, Speed);
  50. }

  51. //读负载,超时返回-1
  52. int ReadLoad(uint8_t ID)
  53. {      
  54.         return readWord(ID, SCSCL_PRESENT_LOAD_L);
  55. }

  56. //读电压,超时返回-1
  57. int ReadVoltage(uint8_t ID)
  58. {      
  59.         return readByte(ID, SCSCL_PRESENT_VOLTAGE);
  60. }

  61. //读温度,超时返回-1
  62. int ReadTemper(uint8_t ID)
  63. {      
  64.         return readByte(ID, SCSCL_PRESENT_TEMPERATURE);
  65. }

  66. //Ping指令,返回舵机ID,超时返回-1
  67. int Ping(uint8_t ID)
  68. {
  69.         int Size;
  70.         uint8_t bBuf[6];
  71.         flushSCS();
  72.         writeBuf(ID, 0, NULL, 0, INST_PING);
  73.         Size = readSCS(bBuf, 6);
  74.         if(Size==6){
  75.                 return bBuf[2];
  76.         }else{
  77.                 return -1;
  78.         }
  79. }

  80. void writeBuf(uint8_t ID, uint8_t MemAddr, uint8_t *nDat, uint8_t nLen, uint8_t Fun)
  81. {
  82.         uint8_t i;
  83.         uint8_t msgLen = 2;
  84.         uint8_t bBuf[6];
  85.         uint8_t CheckSum = 0;
  86.         bBuf[0] = 0xff;
  87.         bBuf[1] = 0xff;
  88.         bBuf[2] = ID;
  89.         bBuf[4] = Fun;
  90.         if(nDat){
  91.                 msgLen += nLen + 1;
  92.                 bBuf[3] = msgLen;
  93.                 bBuf[5] = MemAddr;
  94.                 writeSCS(bBuf, 6);//MemAddr保存的是目标位置在舵机SRAM中的保存地址,如果有目标参数(判断nDat==1),则会从这一位开始输出

  95.         }else{
  96.                 bBuf[3] = msgLen;
  97.                 writeSCS(bBuf, 5);//如果没有目标参数(判断nDat==0)则不输出目标地址,也就只有五位数
  98.         }
  99.         CheckSum = ID + msgLen + Fun + MemAddr;
  100.         if(nDat){
  101.                 for(i=0; i<nLen; i++){
  102.                         CheckSum += nDat;
  103.                 }
  104.                 writeSCS(nDat, nLen);
  105.         }
  106.         CheckSum = ~CheckSum;
  107.         writeSCS(&CheckSum, 1);
  108. }

  109. //普通写指令
  110. //舵机ID,MemAddr内存表地址,写入数据,写入长度
  111. int genWrite(uint8_t ID, uint8_t MemAddr, uint8_t *nDat, uint8_t nLen)
  112. {
  113.         flushSCS();
  114.         writeBuf(ID, MemAddr, nDat, nLen, INST_WRITE);
  115.         return Ack(ID);
  116. }
  117. //读指令
  118. //舵机ID,MemAddr内存表地址,返回数据nData,数据长度nLen
  119. int Read(uint8_t ID, uint8_t MemAddr, uint8_t *nData, uint8_t nLen)
  120. {
  121.         int Size;
  122.         uint8_t bBuf[5];
  123.         flushSCS();
  124.         writeBuf(ID, MemAddr, &nLen, 1, INST_READ);
  125.         if(readSCS(bBuf, 5)!=5){
  126.                 return 0;
  127.         }
  128.         Size = readSCS(nData, nLen);
  129.         if(readSCS(bBuf, 1)){
  130.                 return Size;
  131.         }
  132.         return 0;
  133. }

复制代码








本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

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

本版积分规则

QQ|Archiver|手机版|小黑屋|迪文科技论坛 ( 京ICP备05033781号-1 )

GMT+8, 2024-11-25 05:12 , Processed in 0.094187 second(s), 23 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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