问答

汇集网友智慧,解决技术难题

21ic问答首页 - 51单片机使用74HC595时编写移位代码遇到的问题

单片机 51单片机 使用 编写 移位 遇到

51单片机使用74HC595时编写移位代码遇到的问题

JZ在努力2025-07-28
在编写74HC595相关代码时,关于串行发送,目的是依次点亮LED点阵某一行temp = dat<<i;
SER = temp>>7;

SER  = dat >>7;
dat <<=1;这两种写法是对的,演示结果与预期一致。
但SER  = (dat<<i)>>7;这种写法理应也是对的,但演示结果是先全部点亮然后一次灭一行
请求各位大佬解答
回答 +关注 5
12264人浏览 13人回答问题 分享 举报
13 个回答
  • 这涉及到C语言中的整数提升(integer promotion)和符号扩展(sign extension)问题。
    问题出在表达式求值过程中的数据类型变化
    分步操作时

    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)比依赖移位结果更可靠


  • 估计拆开写的话,就烧了MCU了。
  • 可以分成两步,然后跟踪一下
  • 可以分成两步,然后跟踪一下
  • 好久没用,快忘记了
  • ?????
  • 估计sfr转换不过来,要用if来判断

  • 居然真的还有人在用51?
12下一页

您需要登录后才可以回复 登录 | 注册