之前一周一直在弄I2C和UART,感觉也没做太多的东西,就没单独写,今天算是一起记了。另外今天“海试”,遥控方面没啥大毛病,船也不漏水。不过就是一次下水被水草缠住了;清理了水草第二次下水,L298N驱动芯片过热保护了,船途中失控,差点被水浇了,也挺惊险的。

看到左侧那个喷水的玩意了吗?失控后,不偏不倚就从那个水柱下面钻过去了。三个人差点吓尿了,也没想起来拍照片,可惜了xD
简单来说,树莓派的I2C和UART要用raspi-config打开,或者直接编辑/boot/config.txt也可以,然后就可以用了。然后在程序中作为文件打开,使用ioctl设定了模式,就可以简单的用read(), write()这两个函数读写了。
哦,对了,还修复了一个安卓遥控器在热点模式下不能遥控船的bug。热点模式下,受限广播似乎不会发到热点下面那个子网,而是会发到4G那边,组播224.0.0.1似乎也是。因此需要用Multicast::setNetworkInterface指定要用的网络接口,然后向224.0.0.1发送组播。
先说串口,我用的树莓派3b,听说1和2还好,3的独立串口是没有时钟源的,靠内核提供时钟,但内核时钟又不是很靠谱,所以有时候会失灵。我实际使用时,感觉也是时好时坏的,干脆把祖传的PL2303给插了上去,改用/dev/ttyUSB0,比原来稳定的多。
另外串口一大调试神器,minicom。非常好用,先sudo minicom -s设置了参数,然后save as dfl,之后每次minicom就行了。不过minicom是按一个键发送一个键的ASCII码,有时候可能也会不太方便,这是就需要echo “XXX” > /dev/ttyUSB0了。
I2C的话,有一个i2c-tools,里面有i2cdetect i2cdump i2cget i2cset,分别可以用来探测i2c设备,dump某器件所有寄存器的值,获取/设置某个/某几个寄存器的值,非常方便。具体使用请看man页面。
那么,程序中如何使用这几个接口呢?初始化的时候要特别设置一下,其他的就普通的read和write就可以了,跟Linux下读写文件是一样的。
串口:初始化的时候打开设备文件,并设置串口参数,然后读写。
int Serial::bind(std::string device) {
fd = open(device.c_str(), O_RDWR | O_NOCTTY);
struct termios tio;
if (fd <0)
throw Serial_Exception(Serial_Exception::Device_Not_Found);
bzero(&tio, sizeof(tio));
tio.c_cflag = B115200 | CS8 | CLOCAL | CREAD; // 115200 8N1
tio.c_iflag = 0;
tio.c_oflag = 0;
tio.c_lflag = ICANON;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&tio);
}
void Serial::write(std::string data) {
if (::write(fd, data.c_str(), data.size())!=data.size())
throw Serial_Exception(Serial_Exception::Fail_to_Write);
}
std::string Serial::getline() {
const int buffer_size = 256;
char buffer[buffer_size + 1];
int nbytes = read(fd, buffer, buffer_size);
buffer[nbytes] = 0;
std::string data(buffer);
while (buffer[nbytes-1] != '\n') {
nbytes = read(fd, buffer ,buffer_size);
buffer[nbytes] = 0;
data.append(buffer);
}
return data;
}
I2C:初始化的时候打开设备文件,并指定设备地址,然后写地址,读写/突发读写数据。
void I2C_Device::bind(int deviceID) {
fd = open(szI2CFilename, O_RDWR);
if (fd < 0)
throw I2C_Exception(I2C_Exception::Device_Not_Exist);
if (ioctl(fd, I2C_SLAVE, deviceID) < 0)
throw I2C_Exception(I2C_Exception::Device_Not_Exist);
}
void I2C_Device::setRegister(uint8_t registerID, uint8_t val) {
unsigned char data[2] = {registerID, val};
for (int i = RetryLimit; i; --i) {
if (write(fd, data, 2) == 2)
return;
}
throw I2C_Exception(I2C_Exception::Retry_Limit);
}
uint8_t I2C_Device::getRegister(uint8_t registerID) {
int val;
for (int i = RetryLimit; i; --i)
if (write(fd, ®isterID, 1) == 1)
if (read(fd, &val, 1) == 1)
return val;
throw I2C_Exception(I2C_Exception::Retry_Limit);
}
I2C_Device::~I2C_Device() {
close(fd);
}
其实还蛮简单的?
海试有惊无险的,虽然驱动能力不够是个大问题,但好歹没报废……还行还行,也没白换微信的这个头像。
可以,这很吉祥物。

