21ic问答首页 - 51单片机使用74HC595时编写移位代码遇到的问题
51单片机使用74HC595时编写移位代码遇到的问题
在编写74HC595相关代码时,关于串行发送,目的是依次点亮LED点阵某一行temp = dat<<i;
SER = temp>>7;
和
SER = dat >>7;
dat <<=1;这两种写法是对的,演示结果与预期一致。
但SER = (dat<<i)>>7;这种写法理应也是对的,但演示结果是先全部点亮然后一次灭一行
请求各位大佬解答
SER = temp>>7;
和
SER = dat >>7;
dat <<=1;这两种写法是对的,演示结果与预期一致。
但SER = (dat<<i)>>7;这种写法理应也是对的,但演示结果是先全部点亮然后一次灭一行
请求各位大佬解答

问答
赞0
问题出在表达式求值过程中的数据类型变化
分步操作时
temp = dat << i; // dat是unsigned char,移位后可能提升为int
SER = temp >> 7; // 但此时temp已经存储在变量中,类型确定
单表式达操作时
SER = (dat << i) >> 7;
// 编译器处理过程:
// 1. dat << i → 结果可能是int类型(整数提升)
// 2. 如果dat是有符号char,可能产生符号扩展
// 3. >> 7 对提升后的int进行操作,得到意外结果
方案1:使用无符号类型和强制转换
// 确保dat是无符号类型
unsigned char dat = 0xFF;
// 或者在移位时强制转换
SER = (unsigned char)(dat << i) >> 7;
方案2:使用掩码确保正确位操作
SER = (dat << i) & 0x80 ? 1 : 0; // 检查最高位
方案3: 使用位操作函数
// 定义清晰的位操作函数
void shift_out_byte(uint8_t data) {
for(int i = 7; i >= 0; i--) {
SER = (data >> i) & 0x01; // 明确取第i位
// 产生时钟脉冲
SRCLK = 1;
SRCLK = 0;
}
}
完整的示例
#include <stdint.h>
// 明确的类型定义
#define SER P1_0
#define SRCLK P1_1
#define RCLK P1_2
// 推荐写法 - 清晰明确
void shift_out_safe(uint8_t data) {
for(int8_t i = 7; i >= 0; i--) {
SER = (data >> i) & 0x01; // 取第i位,结果非0即1
SRCLK = 1;
SRCLK = 0;
}
}
// 如果要使用你的原始思路
void shift_out_original(uint8_t data) {
uint8_t temp;
for(int i = 0; i < 8; i++) {
temp = data << i; // 分步操作
SER = temp >> 7; // 避免整数提升问题
SRCLK = 1;
SRCLK = 0;
}
}
避免在复杂表达式中直接移位,特别是涉及不同数据类型的混合运算
使用无符号类型进行位操作
分步操作比单表达式更安全
明确的位提取(& 0x01)比依赖移位结果更可靠
评论
2025-10-27
赞0
评论
2025-09-27
赞0
评论
2025-09-09
赞0
评论
2025-09-09
赞0
评论
2025-09-09
赞0
评论
2025-08-06
赞0
评论
2025-08-06
赞0
评论
2025-07-29
赞0
评论
2025-07-29
您需要登录后才可以回复 登录 | 注册