|
最近帮客户做了一款针对实验柜的舵机控制系统,本着完美主义,我在这里将用T5L屏设计一款高端大气时尚的智能柜管理系统。
(资料陆续更新,欢迎大家提出批评建议)
(dgus工程所用图片均来自于网络,仅供各位朋友交流参考,请勿商用)
首先说一下本智能柜的优势: 1、兼容性: (1)液晶屏(操作面包)兼容性:在设计上采用了T5L标准屏作为主控,直接驱动串行总线舵机,传感器汇总到辅助控制器(如STC系列单片机,再将数据通过串口4发送给液晶屏,在实际开发过程中,只需要根据采用的液晶屏的分辨率改变DGUS工程就行。 (2)舵机兼容性:采用飞特的STS系列串行总线舵机作为驱动,这类舵机的力矩涵盖了4.5KG到40KG,且它们的协议通用 2、安全性:串行总线舵机具有电流、力矩、温度、电压保护功能,其使用安全性要高于常规的电机。 3、可拓展性:串行总线舵机,理论上来说,一个串口支持同时控制254个舵机,即一块液晶屏作为主控,可以带动254个舵机。
关于演示视频的几点说明: 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,将温湿度数据写入迪文屏) - /*****************温湿度更新**********************/
- void dwin_Tempe_humi_update( void)
- {
- uint8_t Tempe_humi_date[20]; //发送给液晶屏的指令
- AHT20_Read_CTdata(CT_data); //读取温度和湿度
-
- Tempe_humi_date[0]=0x5A;
- Tempe_humi_date[1]=0xA5;
- Tempe_humi_date[2]=0x07;
- Tempe_humi_date[3]=0x82;
- Tempe_humi_date[4]=(ADDR_TEMP_HUMI>>8)&0xff;
- Tempe_humi_date[5]=ADDR_TEMP_HUMI&0xff;
- Tempe_humi_date[6]=((CT_data[1] *200*10/1024/1024-500)>>8)&0xff;
- Tempe_humi_date[7]=((CT_data[1] *200*10/1024/1024-500))&0xff;//计算得到温度值(放大了10倍,如果t1=245,表示现在温度为24.5℃)
- Tempe_humi_date[8]=((CT_data[0]*1000/1024/1024)>>8)&0xff;
- Tempe_humi_date[9]=((CT_data[0]*1000/1024/1024))&0xff; //计算得到湿度值(放大了10倍,如果c1=523,表示现在湿度为52.3%)
- Usart_SendString( USART_DWIN,Tempe_humi_date,10);
- }
- /*****************时间更新**********************/
- uint8_t DGUS_RTC_date[40];
- void dwin_time_update( u32 time_value)
- {
- struct rtc_time time;
- unsigned int days,hour_min_sec;
- unsigned int i;
-
- days = time_value / 86400;//一天有86400秒
- hour_min_sec = time_value % 86400;//一天有86400秒
-
- time.hour = hour_min_sec / 3600;//一小时有3600秒
- time.mintute =( hour_min_sec % 3600 ) / 60;//一分钟有60秒
- time.second =( hour_min_sec % 3600 ) % 60;
-
- //年份判断,从1970年开始
- for ( i=1970;days>=days_in_years(i);i++)
- {
- days-=days_in_years(i);
- }
- time.year=i;
- //判断月份
- if (leapyear(i))
- days_in_month[2]=29;
- else
- days_in_month[2]=28;
- for ( i=1;days>=days_in_month;i++)
- {
- days-=days_in_month;
- }
- time.month = i;
- //日期计算
- time.day = days + 1 ;
-
- time.week=RTC_Get_Week(time.year,time.month, time.day);
- DGUS_RTC_date[0]=0x5A;
- DGUS_RTC_date[1]=0xA5;
- DGUS_RTC_date[2]=0x18;
- DGUS_RTC_date[3]=0x82;
- DGUS_RTC_date[4]=(ADDR_RTC_TIME>>8)&0xff;
- DGUS_RTC_date[5]=ADDR_RTC_TIME&0xff;
- DGUS_RTC_date[6]=0x00;
- DGUS_RTC_date[7]=time.hour;//时
- DGUS_RTC_date[8]=0x00;
- DGUS_RTC_date[9]=time.mintute;//分
- DGUS_RTC_date[10]=00;
- DGUS_RTC_date[11]=time.second;//秒
- DGUS_RTC_date[12]=(time.year>>8)&0xff;//年
- DGUS_RTC_date[13]=time.year&0xff;//年
- DGUS_RTC_date[14]=00;
- DGUS_RTC_date[15]=time.month;//月
- DGUS_RTC_date[16]=00;
- DGUS_RTC_date[17]=time.day;//日
-
- DGUS_RTC_date[18]=ascii_8hex[2*weeks(time.week)+0];//(time.week>>8)&0xff;//ascii_8hex[];//
- DGUS_RTC_date[19]=ascii_8hex[2*weeks(time.week)+1];// time.week&0xff;//当前星期
-
- Usart_SendString( USART_DWIN,DGUS_RTC_date,26);
-
- }
- //星期运算
- uint16_t weeks(int weekday)
- {
- // uint16_t asic_2_h;
- if(weekday>6)
- weekday-=7;
- return weekday;
- }
复制代码
本节主要是简单说一下飞特舵机指令协议,供大家做个参考。 飞特舵机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.舵机服务子程序(其他子程序,由于篇幅有限,这里就不写) - int writePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed, uint8_t Fun)
- {
- uint8_t buf[6];
- flushSCS();//清空缓冲区
- u16_to_u8(buf+0, buf+1, Position);
- u16_to_u8(buf+2, buf+3, Time);
- u16_to_u8(buf+4, buf+5, Speed);
- writeBuf(ID, SCSCL_GOAL_POSITION_L, buf, 6, Fun);
- return Ack(ID);
- }
- //写位置指令
- //舵机ID,Position位置,运行时间Time,速度Speed
- int WritePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed)
- {
- return writePos(ID, Position, Time, Speed, INST_WRITE);
- }
- //异步写位置指令
- //舵机ID,Position位置,运行时间Time,速度Speed
- int RegWritePos(uint8_t ID, uint16_t Position, uint16_t Time, uint16_t Speed)
- {
- return writePos(ID, Position, Time, Speed, INST_REG_WRITE);
- }
- void RegWriteAction(void)
- {
- writeBuf(0xfe, 0, NULL, 0, INST_ACTION);
- }
- //写位置指令
- //舵机ID[]数组,IDN数组长度,Position位置,运行时间Time,速度Speed
- void SyncWritePos(uint8_t ID[], uint8_t IDN, uint16_t Position, uint16_t Time, uint16_t Speed)
- {
- uint8_t buf[6];
- u16_to_u8(buf+0, buf+1, Position);
- u16_to_u8(buf+2, buf+3, 0);
- u16_to_u8(buf+4, buf+5, Speed);
- snycWrite(ID, IDN, SCSCL_GOAL_POSITION_L, buf, 6);
- }
- //读位置,超时返回-1
- int ReadPos(uint8_t ID)
- {
- return readWord(ID, SCSCL_PRESENT_POSITION_L);
- }
- //速度控制模式
- int WriteSpe(uint8_t ID, int16_t Speed)
- {
- if(Speed<0){
- Speed = -Speed;
- Speed |= (1<<10);
- }
- return writeWord(ID, SCSCL_GOAL_TIME_L, Speed);
- }
- //读负载,超时返回-1
- int ReadLoad(uint8_t ID)
- {
- return readWord(ID, SCSCL_PRESENT_LOAD_L);
- }
- //读电压,超时返回-1
- int ReadVoltage(uint8_t ID)
- {
- return readByte(ID, SCSCL_PRESENT_VOLTAGE);
- }
- //读温度,超时返回-1
- int ReadTemper(uint8_t ID)
- {
- return readByte(ID, SCSCL_PRESENT_TEMPERATURE);
- }
- //Ping指令,返回舵机ID,超时返回-1
- int Ping(uint8_t ID)
- {
- int Size;
- uint8_t bBuf[6];
- flushSCS();
- writeBuf(ID, 0, NULL, 0, INST_PING);
- Size = readSCS(bBuf, 6);
- if(Size==6){
- return bBuf[2];
- }else{
- return -1;
- }
- }
- void writeBuf(uint8_t ID, uint8_t MemAddr, uint8_t *nDat, uint8_t nLen, uint8_t Fun)
- {
- uint8_t i;
- uint8_t msgLen = 2;
- uint8_t bBuf[6];
- uint8_t CheckSum = 0;
- bBuf[0] = 0xff;
- bBuf[1] = 0xff;
- bBuf[2] = ID;
- bBuf[4] = Fun;
- if(nDat){
- msgLen += nLen + 1;
- bBuf[3] = msgLen;
- bBuf[5] = MemAddr;
- writeSCS(bBuf, 6);//MemAddr保存的是目标位置在舵机SRAM中的保存地址,如果有目标参数(判断nDat==1),则会从这一位开始输出
- }else{
- bBuf[3] = msgLen;
- writeSCS(bBuf, 5);//如果没有目标参数(判断nDat==0)则不输出目标地址,也就只有五位数
- }
- CheckSum = ID + msgLen + Fun + MemAddr;
- if(nDat){
- for(i=0; i<nLen; i++){
- CheckSum += nDat;
- }
- writeSCS(nDat, nLen);
- }
- CheckSum = ~CheckSum;
- writeSCS(&CheckSum, 1);
- }
- //普通写指令
- //舵机ID,MemAddr内存表地址,写入数据,写入长度
- int genWrite(uint8_t ID, uint8_t MemAddr, uint8_t *nDat, uint8_t nLen)
- {
- flushSCS();
- writeBuf(ID, MemAddr, nDat, nLen, INST_WRITE);
- return Ack(ID);
- }
- //读指令
- //舵机ID,MemAddr内存表地址,返回数据nData,数据长度nLen
- int Read(uint8_t ID, uint8_t MemAddr, uint8_t *nData, uint8_t nLen)
- {
- int Size;
- uint8_t bBuf[5];
- flushSCS();
- writeBuf(ID, MemAddr, &nLen, 1, INST_READ);
- if(readSCS(bBuf, 5)!=5){
- return 0;
- }
- Size = readSCS(nData, nLen);
- if(readSCS(bBuf, 1)){
- return Size;
- }
- return 0;
- }
复制代码
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|