理清计算机中的单位:字节、位、比特

一个字节 = 8位二进制 。

字节就是Byte,比特可不是Byte而是bit,是二进制中的单位。

那一个中文字符就一定等于两个字节吗?答案是不一定的,这要看编码表,如果是ASCII码的话一个汉字就是占两个字节,如果是UTF-8的话一个汉字就是占三个字节。

转载于:https://www.cnblogs.com/Wbin01/p/11091605.html

<think>嗯,我现在需要把用户提供的这个函数用HAL库的函数替换掉,不要直接操作寄存器。让我先仔细看一下原来的代码。 首先,函数void led_disp(uint8_t *ucLed)的作用应该是控制LED显示。里面有一个临时变量temp,用来记录当前的LED状态,还有一个静态变量temp_old保存之前的状态,用来判断是否需要更新。然后通过循环将ucLed数组中的每个元素左移后合并到temp里。接着比较temp和temp_old,如果不同,就更新GPIOC和GPIOD的寄存器,最后更新temp_old。 用户要求不要直接操作寄存器,改用HAL库的函数。原来的代码里操作了GPIOC->ODR和GPIOD的BSRR、BRR寄存器。HAL库中常用的函数有HAL_GPIO_WritePin、HAL_GPIO_TogglePin,还有可能需要操作多个引脚的时候用HAL_GPIO_Write多个。 首先,原来的代码处理的是GPIOC的高8(ODR的高字节),因为temp是8的,左移8到高字节。然后取反,可能是因为硬件连接是低电平有效?比如LED的阳极接电源,阴极接GPIO,所以输出低电平时点亮。所以原来的代码用~(temp << 8),也就是将temp的每一取反后放到高8。 那HAL库中如何设置GPIOC的高8呢?每个GPIO端口有多个引脚,比如GPIOC的Pin 8到Pin 15是高8。HAL_GPIO_WritePin可以一次写一个引脚,但逐个写8个的话效率可能不高。不过HAL库没有直接写多个的函数,可能需要循环处理每一。 或者,可以用HAL_GPIO_WriteMultipleState之类的函数,但好像HAL库并没有这样的函数。可能需要用HAL_GPIO_WritePin逐个设置每个引脚的状态。 那temp的每一对应到GPIOC的高8中的某个引脚。例如,ucLed数组中的每个元素对应一个LED的状态,经过移后,temp的第0对应左移7,也就是GPIOC的Pin 8?或者是别的顺序?需要确认硬件连接,假设ucLed[i]对应的是第i个LED,而每个LED连接到GPIOC的某个引脚,比如GPIOC的Pin8到Pin15。 原来的代码中,temp是将ucLed数组的每个元素左移7-i然后或起来,所以ucLed[0]对应的是最高(左移7),也就是Pin 15?或者可能是Pin 8?这里可能需要确认移的方向和硬件连接的对应关系。比如,如果temp的第0对应Pin8,那么左移7-i的话,当i=0时,ucLed[0]左移7,变成bit7,对应Pin8+7=Pin15?或者可能顺序相反? 这部分可能需要更多的硬件信息,但假设原代码是正确的,那么temp的每一对应GPIOC的高字节的某个引脚。例如,temp的bit0对应Pin8,bit1对应Pin9,依此类推,直到bit7对应Pin15。或者反过来?需要确认原代码中的是否正确。 原代码中,temp |= (ucLed[i] << (7 - i)),假设i从0到7循环。对于i=0,左移7,即ucLed[0]的bit0会被移动到bit7的置;i=1,左移6,ucLed[1]的bit0到bit6的置,以此类推。这样,temp的bit7到bit0分别对应ucLed数组的0到7元素。因此,当temp的某个bit为1时,对应到GPIOC的高字节的某个pin需要被设置为相应的电平。但因为原代码中用了~(temp <<8),也就是将temp的每一取反,然后放到高8。例如,temp的bit0对应GPIOC的Pin8,那么当temp的bit0为1时,取反后的值是0,写入到Pin8对应的,即输出低电平,可能点亮LED。 现在,用HAL库替换的话,需要循环处理每个bit,根据temp的值来设置对应的引脚。例如,对于每个bit j(从0到7),对应的GPIOC的Pin是Pin8 + j。然后判断temp的该bit是否为1,如果是,则设置该Pin为低电平(因为原代码用了~temp,所以原来的逻辑是temp的bit为1时,对应的GPIO输出低电平)。 所以,对于每个bit j(0到7),对应的Pin是Pin8 + j。例如: - temp的bit0 → Pin8 - bit1 → Pin9 - ... - bit7 → Pin15 那么,在HAL库中,可以循环这8个Pin,根据temp的每一来设置对应的电平。因为原代码中的temp取反了,所以当temp的某是1时,对应的GPIO应该输出低电平(因为原代码是GPIOC->ODR |= ~(temp << 8)),即原来的temp左移8到高字节,然后取反,所以temp的1变成0,0变成1。所以,如果temp的某是1,对应的GPIO输出低电平;如果是0,输出高电平。 因此,HAL库中的处理应该是:对于每个Pin,如果temp的对应是1,则设置该Pin为低电平(GPIO_PIN_RESET),否则设置为高电平(GPIO_PIN_SET)。 所以,循环每一,从0到7: for (int j = 0; j < 8; j++) { uint16_t pin = GPIO_PIN_8 << j; // 对应Pin8到Pin15 HAL_GPIO_WritePin(GPIOC, pin, (temp & (1 << (7 - j))) ? GPIO_PIN_RESET : GPIO_PIN_SET); } 这里可能需要确认移的方向是否正确。原代码中,ucLed[i]左移7-i,然后将结果合并到temp中。例如,i=0时,ucLed[0]左移7,变成bit7的置,也就是对应temp的最高bit7。这样,当temp被左移8到GPIOC的高字节时,bit7对应的是ODR的bit15,也就是Pin15。所以,这可能意味着ucLed数组中的每个元素对应不同的Pin,比如ucLed[0]对应Pin15,ucLed[1]对应Pin14,依此类推,直到ucLed[7]对应Pin8。这个时候,temp的bit7对应Pin15,bit6对应Pin14,等等。 不过,原代码中的方式可能会让ucLed数组的索引i对应到不同的Pin。例如,ucLed[i]被左移7-i,因此当i=0时,左移7到bit7;i=1,左移6到bit6,依此类推。因此,temp的bit7对应ucLed[0],bit6对应ucLed[1],…,bit0对应ucLed[7]。所以当temp被左移8到高字节时,temp的bit7对应ODR的bit15(Pin15),bit6对应bit14(Pin14),以此类推。因此,temp的每一对应Pin15到Pin8,按顺序排列。 所以,当我们需要将temp的每一对应到GPIOC的Pin15到Pin8时,HAL库的设置应该循环每一,并检查temp的对应是否为1,设置对应的Pin为低电平。 例如,对于temp的bit7(对应ucLed[0])对应的Pin15: if (temp & (1 << 7)) → Pin15设为低电平 同样的,bit6对应Pin14,依此类推,直到bit0对应Pin8。 所以,循环每一j从0到7,对应的Pin是GPIO_PIN_8 + j的置?或者是不是这样?因为GPIO_PIN_0是1<<0,GPIO_PIN_1是1<<1,一直到GPIO_PIN_15是1<<15。所以,Pin8对应的值是0x0100,即1<<8,Pin9是1<<9,依此类推。因此,循环每一j从0到7,对应的Pin应该是GPIO_PIN_8 << j?或者说,从Pin8到Pin15对应的是0x0100 (Pin8), 0x0200 (Pin9), ..., 0x8000 (Pin15)。因此,对应的bit置是第8到第15。 所以,对于temp的每一j(从0到7),对应的Pin是GPIO_PIN_8 + j。例如: temp的bit7 → GPIO_PIN_15 (1 << 15) temp的bit6 → GPIO_PIN_14 (1 << 14) ... temp的bit0 → GPIO_PIN_8 (1 << 8) 这样的话,当j从0到7,对应的temp的bit是7-j。例如,当j=0时,对应bit7;j=1对应bit6,依此类推,直到j=7对应bit0。 所以,循环可以这样写: for (int j = 0; j < 8; j++) { uint16_t pin = GPIO_PIN_8 << j; // 从Pin8到Pin15 // 检查temp的对应bit是否为1,对应的bit是7 - j吗? // 原代码中,ucLed[i]的每一被左移7-i,因此ucLed[0]对应bit7,ucLed[1]对应bit6,依此类推 // 所以temp的bit7对应ucLed[0],bit6对应ucLed[1],..., bit0对应ucLed[7] // 所以,在循环中,我们需要检查temp的bit(7 - j)吗? // 比如,当j=0时,对应Pin8,但是temp的bit7对应Pin15? // 这里可能需要重新理清关系。 或者,可能我的理解有误。原代码中的temp是将ucLed数组中的每个元素左移7-i,然后合并到temp中。例如,对于i=0,ucLed[0]左移7,所以ucLed[0]的bit0会被移到temp的bit7置;i=1,左移6,ucLed[1]的bit0移到temp的bit6置,依此类推。因此,temp的bit7对应ucLed[0],bit6对应ucLed[1],…,bit0对应ucLed[7]。 当temp被左移8,变成GPIOC的高字节(即ODR的bit8到bit15),所以temp的bit7对应ODR的bit15(Pin15),bit6对应ODR的bit14(Pin14),依此类推。所以,temp的每一对应到GPIOC的Pin15到Pin8。 因此,在HAL库中,我们需要为每个Pin从Pin15到Pin8设置对应的电平。例如,temp的bit7对应Pin15,bit6对应Pin14,…,bit0对应Pin8。 因此,循环每一j从0到7,对应的Pin是GPIO_PIN_15 - j。例如: for (int j = 0; j < 8; j++) { uint16_t pin = GPIO_PIN_15 - j; // j=0 → Pin15, j=1→Pin14, ..., j=7→Pin8 uint8_t bit_value = (temp >> (7 - j)) & 0x01; // 或者需要重新计算? } 或者,另一种方式:对于每个Pin从Pin8到Pin15,对应temp的bit0到bit7?或者反过来? 这里可能需要更仔细的分析。原代码中,temp的高对应ucLed的低索引。例如,ucLed[0]被左移到temp的bit7,所以当temp被左移8后,bit7就变成了ODR的bit15(Pin15)。因此,temp的每个bit在左移8后对应到GPIOC的高字节的各个Pin。 因此,temp的bit7对应Pin15,bit6对应Pin14,…,bit0对应Pin8。 所以,在HAL库中,我们需要遍历这些Pin,并根据temp的对应来设置电平。例如,对于Pin15,检查temp的bit7是否为1,设置对应的电平;对于Pin14,检查bit6,依此类推。 因此,循环可以这样写: for (int j = 0; j < 8; j++) { // 对应的Pin是Pin15到Pin8 uint16_t pin = GPIO_PIN_15 - j; // j=0 → Pin15, j=1→Pin14,..., j=7→Pin8 uint8_t bit_pos = 7 - j; // temp的bit置,从7到0 // 检查temp的bit_pos是否为1 if (temp & (1 << bit_pos)) { // 如果bit是1,则设置对应的Pin为低电平 HAL_GPIO_WritePin(GPIOC, pin, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(GPIOC, pin, GPIO_PIN_SET); } } 但这样写的话,当j=0时,pin是Pin15,bit_pos=7;j=1时,pin是Pin14,bit_pos=6,依此类推,直到j=7时,pin是Pin8,bit_pos=0。 这样的处理是否正确? 另外,原代码中temp被取反后设置到高字节,所以原来的逻辑是temp的bit为1时,对应的高字节为0,所以GPIOC的输出为低电平。因此,在HAL库中,当temp的某为1时,对应Pin设为低电平,否则高电平。这和上面的代码逻辑一致。 接下来处理GPIOD的部分。原代码中: GPIOD->BSRR |= 0x01 << 2; // 设置 GPIOD 第2 GPIOD->BRR |= 0x01 << 2; // 重置 GPIOD 第2 BSRR寄存器的低16用于设置(置1),高16用于清除(置0)。所以,BSRR |= 0x01 << 2 即设置Bit2为高电平。然后BRR寄存器用来清除,BRR |= 0x01 <<2 即设置Bit2为低电平。所以这两条语句的效果是将GPIOD的Bit2先置高,再置低,可能产生一个脉冲信号,用于锁存或其他控制功能。 在HAL库中,可以使用HAL_GPIO_WritePin函数来实现这个操作。例如: HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); // 设置Bit2为高 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // 设置Bit2为低 或者,可能更高效的是使用HAL_GPIO_TogglePin,但这里需要明确先高后低,形成一个脉冲。所以直接两次写操作即可。 不过,原代码中这两条语句之间是否有延时?如果没有,可能这个脉冲非常短暂,可能硬件需要一定的保持时间。但原代码可能已经满足硬件要求,所以按照用户的要求,替换为HAL函数即可。 综上,整个函数的HAL库版本应该如下: 1. 计算temp的值,和原代码相同。 2. 比较temp和temp_old,不同则更新。 3. 更新时,循环设置GPIOC的Pin8到Pin15的电平,根据temp的各值。 4. 操作GPIOD的Bit2,先置高再置低。 所以,最终的代码可能如下: void led_disp(uint8_t *ucLed) { uint8_t temp = 0x00; static uint8_t temp_old = 0xff; for (int i = 0; i < 8; i++) { temp |= (ucLed[i] << (7 - i)); } if (temp != temp_old) { // 更新GPIOC的Pin8到Pin15 for (int j = 0; j < 8; j++) { uint16_t pin = GPIO_PIN_8 << j; // 这样得到的是Pin8到Pin15? // 或者需要调整循环顺序? // 正确的Pin对应应该是,temp的bit7对应Pin15,bit6对应Pin14,依此类推 // 所以,另一种方式: uint16_t pin = GPIO_PIN_15 - j; uint8_t bit_pos = 7 - j; if (temp & (1 << bit_pos)) { HAL_GPIO_WritePin(GPIOC, pin, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(GPIOC, pin, GPIO_PIN_SET); } } // 或者另一种循环方式: for (int bit_pos = 0; bit_pos < 8; bit_pos++) { uint16_t pin = GPIO_PIN_8 + bit_pos; // 这样对应Pin8到Pin15? // 但是temp的bit0对应ucLed[7],经过移后,temp的bit0对应原来的ucLed[7]左移0,即temp的bit0 // 但是temp被左移8后,temp的bit0对应ODR的bit8,即Pin8? // 所以,原代码中的temp左移8后,temp的bit0对应ODR的bit8(Pin8),temp的bit7对应ODR的bit15(Pin15) // 所以,在HAL库中,每个bit_pos从0到7对应GPIOC的Pin8到Pin15 // 因此,循环bit_pos从0到7,对应的Pin是GPIO_PIN_8 + bit_pos // 例如,bit_pos=0 → Pin8,bit_pos=7 → Pin15 // 那么,temp的每个bit_pos对应ucLed的7 - bit_pos?因为ucLed[i]左移7-i,i从0到7: // 例如,当i=0,ucLed[0]左移7到temp的bit7,i=1左移6到temp的bit6,依此类推,i=7左移0到temp的bit0 // 因此,temp的bit_pos对应的ucLed的i是7 - bit_pos? // 但这里需要设置的是GPIOC的Pin8到Pin15,对应temp的bit0到bit7? // 原代码中,temp左移8后,temp的bit0对应ODR的bit8(Pin8),bit7对应ODR的bit15(Pin15) // 所以,temp的bit_pos(0-7)对应GPIOC的Pin8 + bit_pos // 因此,循环每个bit_pos,检查temp的该是否为1,设置对应的Pin为低电平 uint8_t bit_value = (temp >> bit_pos) & 0x01; if (bit_value) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 + bit_pos, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 + bit_pos, GPIO_PIN_SET); } } // 注意,这样是否正确?因为原代码中,temp左移8,所以temp的bit0对应ODR的bit8(Pin8),bit7对应ODR的bit15(Pin15) // 所以,在HAL库中,temp的bit0对应Pin8,bit1对应Pin9,依此类推,bit7对应Pin15 // 所以,循环bit_pos从0到7,对应的Pin是GPIO_PIN_8 + bit_pos // 然后,根据temp的该bit_pos是否为1,设置对应的Pin为低电平 // 例如,当bit_pos=0,检查temp的bit0,对应Pin8,如果为1,Pin8设为低电平 // 这样是否正确? // 原代码中,设置的是GPIOC的高字节为~temp,即temp的每一取反,然后放在高字节 // 例如,temp的bit0为1 → 高字节的bit8为0 → Pin8输出低电平 // 因此,HAL库中,如果temp的某bit为1,对应的Pin设为低电平,否则高电平 // 所以,正确的循环应该是: for (int bit_pos = 0; bit_pos < 8; bit_pos++) { uint16_t pin = GPIO_PIN_8 << bit_pos; // 错误,这样会是Pin8左移bit_pos,比如bit_pos=0是Pin8,bit_pos=1是Pin9*2=0x0200(Pin9) // 正确的Pin应该是GPIO_PIN_8 + bit_pos?不对,因为GPIO_PIN_8是0x0100(1<<8),GPIO_PIN_9是0x0200(1<<9),依此类推。 // 所以,对应的Pin应该是GPIO_PIN_8 << bit_pos吗?或者bit_pos对应的是0到7,对应的Pin是Pin8到Pin15,即每个bit_pos对应的Pin是GPIO_PIN_8 + bit_pos? // 不,GPIO_PIN_8是第8个引脚,对应的宏是(1 << 8),即0x0100。GPIO_PIN_9是(1 <<9),即0x0200。所以,当bit_pos为0到7时,对应的Pin应该是(1 << (8 + bit_pos))。例如: uint16_t pin = 1 << (8 + bit_pos); // 这样,当bit_pos=0时是Pin8,bit_pos=7时是Pin15 // 所以,对应的Pin可以这样生成: uint16_t pin = GPIO_PIN_8 << bit_pos; // 但GPIO_PIN_8已经是(1<<8),左移bit_pos的话,当bit_pos=0是Pin8,bit_pos=1是Pin9,依此类推,对吗? // 是的,例如: // bit_pos=0: GPIO_PIN_8 <<0 = 0x0100 → Pin8 // bit_pos=1: 0x0100 <<1 = 0x0200 → Pin9 // ...一直到bit_pos=7: 0x0100 <<7 = 0x8000 → Pin15 // 因此,循环可以这样写: uint16_t pin = GPIO_PIN_8 << bit_pos; if (temp & (1 << bit_pos)) { HAL_GPIO_WritePin(GPIOC, pin, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(GPIOC, pin, GPIO_PIN_SET); } } // 这样是否正确? // 例如,temp的bit0对应Pin8,如果temp的bit0是1,则Pin8设为低电平;否则高电平。这和原代码中的逻辑一致,因为原代码将temp取反后设置到高字节。 // 因此,这个循环是正确的。 // 接下来处理GPIOD的Bit2,先置高再置低 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); temp_old = temp; } } 但这里有一个疑问:原代码中的GPIOD->BSRR |= 0x01 <<2,即设置Bit2为1,然后GPIOD->BRR |=0x01<<2,即设置Bit2为0。这相当于先拉高再拉低,产生一个上升沿和下降沿的脉冲。在HAL库中,用两次WritePin来实现这一点是正确的。 综上,替换后的函数应该像这样: 用循环设置GPIOC的Pin8到Pin15,根据temp的每一的值,设置为低或高电平。然后操作GPIOD的Pin2产生一个脉冲。 现在,检查是否所有的寄存器操作都被替换为HAL函数。原来的GPIOC->ODR &= 0x00ff; 清除高字节,然后设置新的值。但用HAL库的话,无法直接操作整个端口的高字节,只能逐个设置每个Pin的状态。所以,原来的代码是清除高字节并设置新的值,而HAL库的方式是逐个设置每个Pin,因此不需要先清除,因为每个Pin都会被显式设置。这可能更可靠,因为原来的代码可能受其他的影响,但HAL库的逐个设置会覆盖所有相关。 因此,替换后的代码是正确的。</think>以下是用HAL库函数重构后的代码实现及详细解析: ```c void led_disp(uint8_t *ucLed) { uint8_t temp = 0x00; static uint8_t temp_old = 0xff; // 合并LED状态到临时变量temp for (int i = 0; i < 8; i++) { temp |= (ucLed[i] << (7 - i)); } // 仅当状态变化时才更新显示 if (temp != temp_old) { // 更新GPIOC引脚状态(Pin8-Pin15) for (int bit_pos = 0; bit_pos < 8; bit_pos++) { // 计算目标引脚编号(Pin8到Pin15) uint16_t pin = GPIO_PIN_8 << bit_pos; // 根据bit值设置电平(取反逻辑:1→低电平,0→高电平) HAL_GPIO_WritePin(GPIOC, pin, (temp & (1 << bit_pos)) ? GPIO_PIN_RESET : GPIO_PIN_SET); } // 生成GPIO控制脉冲(模仿原代码的BSRR/BRR操作) HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); // 拉高 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // 拉低 temp_old = temp; // 更新旧状态记录 } } ``` ### 关键修改点说明: 1. **LED状态合并逻辑** 保留原有`temp`变量的计算方式,通过循环将`ucLed`数组中每个元素的比特映射到`temp`的对应置。例如: - `ucLed[0]`左移7占据`temp`的最高(bit7) - `ucLed[7]`不移占据`temp`的最低(bit0) 2. **GPIO引脚控制** - **旧代码**:直接操作寄存器`GPIOC->ODR`,一次性设置高8(Pin8-Pin15) - **新代码**:通过`HAL_GPIO_WritePin()`逐设置引脚状态 - `GPIO_PIN_8 << bit_pos`:动态计算引脚编号(bit_pos=0对应Pin8,bit_pos=7对应Pin15) - `(temp & (1 << bit_pos)) ? ...`:根据`temp`的比特值决定电平状态,实现原代码的**取反逻辑**(1→低电平,0→高电平) 3. **控制脉冲生成** - **旧代码**:通过`BSRR`和`BRR`寄存器实现GPIO快速翻转 - **新代码**:使用两次`HAL_GPIO_WritePin()`模拟上升沿和下降沿,形成短脉冲信号 ### 注意事项: 1. **硬件连接验证** 需确认LED实际连接的GPIO引脚是否与代码中的`GPIO_PIN_8`起始的编号匹配。若硬件设计不同,需调整引脚编号的生成逻辑。 2. **性能优化** 若对实时性要求较高,可考虑以下优化: - 预计算所有引脚编号的掩码(如`GPIO_PIN_8 | GPIO_PIN_9 | ...`) - 使用`HAL_GPIO_WriteMultiplePins()`(需目标MCU支持) 3. **电平取反逻辑** 原代码中的`~(temp << 8)`表明LED为**低电平驱动**。若硬件设计为高电平驱动,需移除电平取反逻辑(将`GPIO_PIN_RESET`和`GPIO_PIN_SET`互换)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值