我在更改激光雷达传感器的地址时遇到问题。它的默认地址是 7 位的 0x62,但由于微控制器只需要 8 位,所以地址现在是 0xC4。这是我写的代码:
void change_address(char new_addr)
{
char addr = 0x16;
char tab[2];
i2c.write(LIDAR_ADDR,&addr, 1);
i2c.read(LIDAR_ADDR,tab,2);
char tab1[2] = {0x18,0};
tab1[1] = tab[0];
i2c.write(LIDAR_ADDR,tab1,2);
char tab2[2] = {0x19,0};
tab2[1] = tab[1];
i2c.write(LIDAR_ADDR,tab2,2);
char tab3[2] = {0x1a,new_addr};
i2c.write(LIDAR_ADDR,tab3,2);
char tab4[2] = {0x1e,0x08};
i2c.write(LIDAR_ADDR,tab4,2);
}
我已经按照所有步骤操作了,但是当我要查看新地址时,我分配的新地址不存在。有谁知道原因吗?提前谢谢你
我做了这段代码来检查 I2C 组件是否存在,这段代码在激光雷达传感器的默认地址下运行良好,但当我尝试更改激光雷达的地址时它不再起作用
int main() {
int i;
int rep;
printf("Debut du Scan...\n\r");
char new_add = 0x46 << 1;
change_address(new_add);
for (i = 0x00; i <= 0xFF; i = i + 1)
{
i2c.start(); // Start
rep = i2c.write(i); // Envoi d’une adresse, y a-t-il une
if (rep == 1) // réponse ?
{
printf("Test de l’adresse %x Composant I2C present !!\n\r", i);
}
else
{
printf("Test de l’adresse %x ... rien ... \n\r",i);
}
i2c.stop(); // Stop
wait(0.1);
}
printf("Fin du Scan...\n\r");
}
我认为你误解了 I2C 的工作原理。 I2C 地址默认为 7 位(有 10 位模式,但我们将在此处忽略),但是为了执行 I2C 通信,您所做的是让主机/主机通过 I2C 启动(设置 SDA /SCL 电平适当),然后传输控制字节(由 7 位 I2C 地址 + 1 位组成,指示您是否正在使用读/写操作,因此对于写入,这将是
(0x62 << 1) | 0
(0xc4
),对于读取将是(0x62 << 1) | 1
(0xc5
)),等待总线上的设备确认该控制字节,然后读取总线上的数据(将每个字节作为主机确认,最后一个字节除外)或进一步发送字节(并等待总线上每个设备的 ACK),最后发送一个 I2C 停止序列。
此外,与大多数I2C设备的交互通常是这样的:你首先要发送一个或多个字节表示你要与之交互(读/写)的设备上的寄存器,然后你才真正执行写/读操作.如果要向设备写入数据,这很简单:首先传输控制字节,然后传输寄存器,然后将要写入的数据传输到该寄存器。如果您正在从设备读取数据,它会变得更加复杂,因为您首先必须在发送寄存器的地方启动写操作(但寄存器没有数据),然后重新启动 I2C 序列以启动读操作到读取该寄存器的数据。
我不完全知道你在这里使用的是哪个 I2C 库,但是通过阅读你的代码,我怀疑你会想要做类似下面的事情来改变设备的地址(我也抽象了读/编写寄存器函数,以便在与设备自身通信时可以重复使用这些函数;请注意,它们假设您始终有一个字节用于寄存器,一个字节用于寄存器数据——如果您想与其他 I2C 设备通信,这可能会有所不同——你必须阅读那里的文档):
// Read a register from the I2C device
// This implementation will write the register index
// to the I2C device and then read the resulting
// value. (This only works for I2C devices that
// follow this very addressing scheme.)
//
// Parameters:
// i2c_addresss: The 7bit (!) I2C address of the device
// device_register: The 8bit device register to read
//
// Return value:
// The device register
unsigned char read_register(unsigned char i2c_address, unsigned char device_register)
{
i2c.start();
// send control byte (writing data)
bool rep = i2c.write((i2c_address << 1) | 0);
if (!rep) {
i2c.stop();
// feel free to do any kind of error handling you like here
throw std::runtime_error("I2C transaction failed");
}
// send the register we want to read to the device
rep = i2c.write(device_register);
if (!rep) {
i2c.stop();
// feel free to do any kind of error handling you like here
throw std::runtime_error("I2C transaction failed");
}
// now we want to read from the I2C device
// for this we restart the I2C transaction
// Note: most I2C devices don't require an
// I2C stop before the next I2C start
// here, but feel free to insert one
// if this doesn't work with your device
i2c.start();
// send control byte (reading data)
bool rep = i2c.write((i2c_address << 1) | 1);
if (!rep) {
i2c.stop();
// feel free to do any kind of error handling you like here
throw std::runtime_error("I2C transaction failed");
}
// now I'm only guessing how your I2C library works...
// no idea if i2c.read() actually looks this way in your case...
unsigned char result = i2c.read();
i2c.stop();
}
// Write a register to the I2C device
// This implementation will write the register index, followed
// by the register value, to the I2C device. (This only works
// for I2C devices that follow this very addressing scheme.)
//
// Parameters:
// i2c_addresss: The 7bit (!) I2C address of the device
// device_register: The 8bit device register to read
// value: The register value to write
void write_register(unsigned char i2c_address, unsigned char device_register, unsigned char value)
{
i2c.start();
// send control byte (writing data)
bool rep = i2c.write((i2c_address << 1) | 0);
if (!rep) {
i2c.stop();
// feel free to do any kind of error handling you like here
throw std::runtime_error("I2C transaction failed");
}
// send the register we want to write to the device
rep = i2c.write(device_register);
if (!rep) {
i2c.stop();
// feel free to do any kind of error handling you like here
throw std::runtime_error("I2C transaction failed");
}
// send the value of the register to the device
rep = i2c.write(value);
if (!rep) {
i2c.stop();
// feel free to do any kind of error handling you like here
throw std::runtime_error("I2C transaction failed");
}
i2c.stop();
}
void update_address_of_lidar(unsigned char new_address)
{
// This is the 7bit (!) address of the device
unsigned char orig_address = 0x62;
// read out the serial number of the I2C device
unsigned char sn_high = read_register(orig_address, 0x16);
unsigned char sn_low = read_register(orig_address, 0x17);
// re-write the serial number of the device to unlock
// the corresponding register
write_register(orig_address, 0x18, sn_high);
write_register(orig_address, 0x19, sn_low);
// write the new i2c address to the device
write_register(orig_address, 0x1a, new_address);
// attempt to re-read the serial number from the new
// address (to see if assignment has worked)
unsigned char sn_high2 = read_register(new_address, 0x16);
unsigned char sn_low2 = read_register(new_address, 0x17);
if (sn_high2 != sn_high || sn_low2 != sn_low) {
// feel free to do any kind of error handling you like here
throw std::runtime_error("Could not update the I2C address successfully");
}
// Now that we know the new address works we can disable
// the default address
// (Note that while the instructions of the manual say
// to write 0x08 here, the register documentation for
// the register 0x1e indicates that 0x01 disables the
// original I2C address. So if the following doesn't
// work to disable the original address, you can also
// try 0x01 here...)
write_register(orig_address, 0x1e, 0x08);
}
// Other code:
// NB: if you want the new control byte for writing
// to be 0x46, then the corresponding 7bit (!)
// address would actually be 0x23
unsigned char new_address = 0x46;
update_address_of_lidar(new_address);
标准免责声明: