之前一周一直在弄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); }
其实还蛮简单的?
海试有惊无险的,虽然驱动能力不够是个大问题,但好歹没报废……还行还行,也没白换微信的这个头像。
可以,这很吉祥物。