开发日志 170411

之前一周一直在弄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, &registerID, 1) == 1)
                        if (read(fd, &val, 1) == 1)
                                return val;
        throw I2C_Exception(I2C_Exception::Retry_Limit);
}

I2C_Device::~I2C_Device() {
        close(fd);
}

其实还蛮简单的?

海试有惊无险的,虽然驱动能力不够是个大问题,但好歹没报废……还行还行,也没白换微信的这个头像。

可以,这很吉祥物。

发表评论