BH60 是一款多圈绝对值旋转编码器。本文通过实验验证它的开发使用方式。根据 BH60绝对位置旋转编码器编程资料 中的选型指南,可以知道实验的旋转编码器的性能为:
▲ BH60的名牌和内部结构示意图
根据编码器铭牌信息,可以知道它使用MODBUS RTU协议。传感器的引线定义由 BH60 给出。
按照上述顺序完成实验接口的焊接和制作。如下:
▲ 传感器的功能线定义
PIN | 电源+ | 电源- | A+ | B- | 置零 | 编程 |
---|---|---|---|---|---|---|
1 | 5.056200 | 0.019221 | 3.177800 | 0.065227 | 0.024253 | 0.024475 |
使用STC8H1K28作为实验控制MCU。设计相应基于面包板连接的实验电路。
▲ 实验电路原理图
▲ 实验电路板
□ 工作参数 : 工作时钟:35MHz,调试串口460800bps。
□ 测试UART2波特率
在35MHz时钟频率下, UART2输出19200的波特率设置。 T 2 = 0 x F E 38 T_2 = 0xFE38 T2=0xFE38。
▲ 输出0x55波形
▲ 发送波形以及MAX487的DIR控制波形
□ 将MAX487模块连入
将 MAX487制作RS485总线接口模块 接入STC8H1K28外部端口。
▲ MAX487模块连入单片机接口引线
使用另外一块MAX487对输出总线进行接收。验证前面发送数据的完整性。
▲ 总线波形以及487接收波形|上:总线A线信号;下:487接收信号
□ 将BH60 接入总线
根据前面传感器接口定义,将传感器接入MAX487模块的总线电路。
根据传感器型号,BH60使用 MODBUS 协议来传递信息。相关的通信协议可以在 BH60的MODBUS 协议中给出。
在MODBUS的ADU中,最后两个字节为 MODBUS CRC ,它的实现方式见下面的C语言代码。
// Compute the MODBUS RTU CRC
UInt16 ModRTU_CRC(byte[] buf, int len)
{
UInt16 crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= (UInt16)buf[pos]; // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--) { // Loop over each bit
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
}
else // Else LSB is not set
crc >>= 1; // Just shift right
}
}
// Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
return crc;
}
★ 注意:CRC传输的时候是 低字节在前,高字节在后
▲ BH60读出数据波形
//------------------------------------------------------------------------------
unsigned int ModbusCRC(unsigned char * pByte, int nLength) {
unsigned int nCRC;
unsigned int i;
unsigned char ucByte, j;
nCRC = 0xffff;
for(i = 0; i < nLength; i ++) {
ucByte = *(pByte + i);
nCRC ^= (unsigned int)ucByte;
for(j = 0; j < 8; j ++) {
if((nCRC & 0x1) != 0) {
nCRC >>= 1;
nCRC ^= 0xA001;
} else nCRC >>= 1;
}
}
return nCRC;
}
//------------------------------------------------------------------------------
void BH60AppendCRC(unsigned char ucLength) {
unsigned int nCRC;
nCRC = ModbusCRC(g_ucBH60Buffer, ucLength);
g_ucBH60Buffer[ucLength + 1] = (unsigned char)(nCRC >> 8);
g_ucBH60Buffer[ucLength] = (unsigned char)nCRC;
}
long BH60Buffer2Number(void) {
unsigned long lnNumber;
if(g_ucBH60Buffer[6] & 0x80)
lnNumber = 0xff;
else lnNumber = 0;
lnNumber = (lnNumber << 8) + g_ucBH60Buffer[6];
lnNumber = (lnNumber << 8) + g_ucBH60Buffer[3];
lnNumber = (lnNumber << 8) + g_ucBH60Buffer[4];
return (long)lnNumber;
}
else IFARG0("readbh60") {
sscanf(SDA(1), "%d", &nNumber);
for(i = 0; i < nNumber; i ++) {
printf("%ld ", BH60ReadNumber());
WaitTime(50);
}
printf("\r\n");
} else IFARG0("readbh60b") {
lnNumber = BH60ReadNumber();
SendChar((unsigned char)(lnNumber));
lnNumber >>= 8;
SendChar((unsigned char)(lnNumber));
lnNumber >>= 8;
SendChar((unsigned char)(lnNumber));
}
手动旋转传感器10圈,然后读取输出的角度,大约41074。平均下来每圈为4107.4。这个参数对应每圈4096数据。
▲ 手动旋转传感器
▲ 旋转10圈读取的数据
通过STC8H1K28通过485总线的MODBUS读取传感器的数据,测试了旋转传感器的基本参数以及通信协议。
/*
**==============================================================================
** BH60.C: -- by Dr. ZhuoQing, 2020-07-13
**
**==============================================================================
*/
#include
//------------------------------------------------------------------------------
#define BH60_GLOBALS 1 // Define the global variables
#include "BH60.H"
#include "MAIN.H"
#include "STC8H.H"
#include "C51BASIC.H"
//------------------------------------------------------------------------------
void BH60Init(unsigned char ucAddress) {
g_ucBH60Address = ucAddress;
}
//------------------------------------------------------------------------------
unsigned int ModbusCRC(unsigned char * pByte, int nLength) {
unsigned int nCRC;
unsigned int i;
unsigned char ucByte, j;
nCRC = 0xffff;
for(i = 0; i < nLength; i ++) {
ucByte = *(pByte + i);
nCRC ^= (unsigned int)ucByte;
for(j = 0; j < 8; j ++) {
if((nCRC & 0x1) != 0) {
nCRC >>= 1;
nCRC ^= 0xA001;
} else nCRC >>= 1;
}
}
return nCRC;
}
//------------------------------------------------------------------------------
void BH60AppendCRC(unsigned char ucLength) {
unsigned int nCRC;
nCRC = ModbusCRC(g_ucBH60Buffer, ucLength);
g_ucBH60Buffer[ucLength + 1] = (unsigned char)(nCRC >> 8);
g_ucBH60Buffer[ucLength] = (unsigned char)nCRC;
}
//------------------------------------------------------------------------------
void BH60SendBuffer(unsigned char ucLength) {
unsigned char i;
BH60AppendCRC(ucLength);
ON(DIR_PIN);
for(i = 0; i < ucLength + 2; i ++) {
UART2SendChar(g_ucBH60Buffer[i]);
}
OFF(DIR_PIN);
UART2_CLEAR;
}
//------------------------------------------------------------------------------
void BH60ReadData2Buffer(void) {
unsigned char i, c;
g_ucBH60Buffer[0] = g_ucBH60Address;
g_ucBH60Buffer[1] = 0x3;
g_ucBH60Buffer[2] = 0x0;
g_ucBH60Buffer[3] = 0x3;
g_ucBH60Buffer[4] = 0x0;
g_ucBH60Buffer[5] = 0x2;
BH60SendBuffer(6);
for(i = 0; i < 9; i ++) {
if(UART2ReceChar(&c)) return;
g_ucBH60Buffer[i] = c;
}
}
void BH60ReadConfig2Buffer(void) {
unsigned char i, c;
g_ucBH60Buffer[0] = g_ucBH60Address;
g_ucBH60Buffer[1] = 0x3;
g_ucBH60Buffer[2] = 0x0;
g_ucBH60Buffer[3] = 0x0;
g_ucBH60Buffer[4] = 0x0;
g_ucBH60Buffer[5] = 0x3;
BH60SendBuffer(6);
for(i = 0; i < 11; i ++) {
if(UART2ReceChar(&c)) return;
g_ucBH60Buffer[i] = c;
}
}
//------------------------------------------------------------------------------
long BH60Buffer2Number(void) {
unsigned long lnNumber;
if(g_ucBH60Buffer[6] & 0x80)
lnNumber = 0xff;
else lnNumber = 0;
lnNumber = (lnNumber << 8) + g_ucBH60Buffer[6];
lnNumber = (lnNumber << 8) + g_ucBH60Buffer[3];
lnNumber = (lnNumber << 8) + g_ucBH60Buffer[4];
return (long)lnNumber;
}
//------------------------------------------------------------------------------
long BH60ReadNumber(void) {
BH60ReadData2Buffer();
return BH60Buffer2Number();
}
//==============================================================================
// END OF THE FILE : BH60.C
//------------------------------------------------------------------------------
/*
**==============================================================================
** BH60.H: -- by Dr. ZhuoQing, 2020-07-13
**
** Description:
**
**==============================================================================
*/
#ifndef __BH60__
#define __BH60__
//------------------------------------------------------------------------------
#ifdef BH60_GLOBALS
#define BH60_EXT
#else
#define BH60_EXT extern
#endif // BH60_GLOBALS
//------------------------------------------------------------------------------
#define BH60_ADDRESS 1
//==============================================================================
void BH60Init(unsigned char ucAddress);
//------------------------------------------------------------------------------
#define BH60_BUFFER 16
BH60_EXT unsigned char xdata g_ucBH60Buffer[BH60_BUFFER];
BH60_EXT unsigned char xdata g_ucBH60Address;
unsigned int ModbusCRC(unsigned char * pByte, int nLength);
void BH60AppendCRC(unsigned char ucLength);
//------------------------------------------------------------------------------
void BH60SendCharBuffer(unsigned char ucLength);
void BH60ReadData2Buffer(void);
void BH60ReadConfig2Buffer(void);
long BH60Buffer2Number(void);
//------------------------------------------------------------------------------
long BH60ReadNumber(void);
//==============================================================================
// END OF THE FILE : BH60.H
//------------------------------------------------------------------------------
#endif // __BH60__
实验电路板硬件AD工程文件:AD\Test\2020\Tools\BUS487STC8H.SchDoc ↩︎
单片机软件工程文件:C51\STC\Test\2020\Tools\BUS487STC8H1K28\BUS487STC8H1K28.uvproj ↩︎