文章目录
- STC15 - C51 - 操作寄存器时, 不要操作不相关的位
- 概述
- 笔记
- 生成.i文件的选项
- 编译工程后, 查看.list文件和.i文件
- .c文件相关内容
- .list文件
- .i文件
- 通过.i文件(预处理文件), 就可以看到最终实现代码有啥区别了
- 不好使的代码
- 好使的代码
- 总结
- END
STC15 - C51 - 操作寄存器时, 不要操作不相关的位
概述
在集成模块代码, 突然发现了一个奇怪的现象, 过了一段初始化代码(初始化T0定时器)后, 串口打印不出东西了.
反复确认, 在这段初始化代码前面, 就可以串口输出, 过了这段初始化代码, 就不能串口输出. 这段初始化代码一定有问题.
我整的这个测试工程中, 因为要根据不同的功能, 去执行不同的初始化, 我其他地方还有一段T0初始化代码, 在初始化后, 是可以串口输出的.
眼睛真看不出来啥区别, 最后查看.i文件(预处理文件), 看出区别了. 原来不好使的那段代码, 直接给寄存器赋值(影响了其他功能的寄存器控制位). 好使的那段代码, 只给寄存器相关的位赋值.
这就是区别.
笔记
生成.i文件的选项
编译工程后, 查看.list文件和.i文件
先看列表文件.lst
e.g. 调试的.c文件为uart_cmd_test_pwm_as_adc.c
那么 .list 文件就为uart_cmd_test_pwm_as_adc.lst, .i文件就为 uart_cmd_test_pwm_as_adc.i
.c文件相关内容
PrintString1("PWM和ADC测试程序, 输入占空比为 0~256! 输入9999退出\r\n"); //SUART1发送一个字符串
display_index = 0;
// Timer0初始化
// #define __UART_CMD_TEST_PWM_AS_ADC_C__USE_ASM_INIT__
#ifdef __UART_CMD_TEST_PWM_AS_ADC_C__USE_ASM_INIT__
// 过了这里, 串口打印就打不出东西来了...
// EA = 0;
AUXR = 0x80; //Timer0 set as 1T, 16 bits timer auto-reload,
TH0 = (u8)(Timer0_Reload / 256);
TL0 = (u8)(Timer0_Reload % 256);
ET0 = 1; //Timer0 interrupt enable
TR0 = 1; //Tiner0 run
/*
AUXR = 0x80;
TH0 = (u8)((65536UL -(22118400L / 1000)) / 256);
TL0 = (u8)((65536UL -(22118400L / 1000)) % 256);
ET0 = 1;
TR0 = 1;
*/
// EA = 1;
#else
// 但是用宏写的初始化, 过了这里, 串口打印可以打出东西...
// 为啥呢?
Timer0_1T(); //Timer0 set as 1T, 16 bits timer auto-reload
Timer0_Load(Timer0_Reload);
Timer0_InterruptEnable(); //Timer0 interrupt enable
Timer0_Run(); //Tiner0 run
/*
// uart_cmd_test_pwm_as_adc.i 最终的代码
AUXR |= (1<<7);
TH0 = ((65536UL -(22118400L / 1000))) / 256, TL0 = ((65536UL -(22118400L / 1000))) % 256;
ET0 = 1;
TR0 = 1;
*/
#endif // #ifdef __UART_CMD_TEST_PWM_AS_ADC_C__USE_ASM_INIT__
PrintString1("PWM和ADC测试程序, 输入占空比为 0~256! 输入9999退出\r\n"); //SUART1发送一个字符串
.list文件
58 1 // #define __UART_CMD_TEST_PWM_AS_ADC_C__USE_ASM_INIT__
59 1 #ifdef __UART_CMD_TEST_PWM_AS_ADC_C__USE_ASM_INIT__
// 过了这里, 串口打印就打不出东西来了...
// EA = 0;
AUXR = 0x80; //Timer0 set as 1T, 16 bits timer auto-reload,
C51 COMPILER V9.60.0.0 UART_CMD_TEST_PWM_AS_ADC 12/16/2022 14:30:28 PAGE 42
TH0 = (u8)(Timer0_Reload / 256);
TL0 = (u8)(Timer0_Reload % 256);
ET0 = 1; //Timer0 interrupt enable
TR0 = 1; //Tiner0 run
/*
AUXR = 0x80;
TH0 = (u8)((65536UL -(22118400L / 1000)) / 256);
TL0 = (u8)((65536UL -(22118400L / 1000)) % 256);
ET0 = 1;
TR0 = 1;
*/
// EA = 1;
#else
78 1 // 但是用宏写的初始化, 过了这里, 串口打印可以打出东西...
79 1 // 为啥呢?
80 1 Timer0_1T(); //Timer0 set as 1T, 16 bits timer auto-reload
81 1 Timer0_Load(Timer0_Reload);
82 1 Timer0_InterruptEnable(); //Timer0 interrupt enable
83 1 Timer0_Run(); //Tiner0 run
84 1
85 1 /*
86 1 // uart_cmd_test_pwm_as_adc.i 最终的代码
87 1 AUXR |= (1<<7);
88 1 TH0 = ((65536UL -(22118400L / 1000))) / 256, TL0 = ((65536UL -(22118400L / 1000))) % 256;
89 1 ET0 = 1;
90 1 TR0 = 1;
91 1 */
92 1
93 1 #endif // #ifdef __UART_CMD_TEST_PWM_AS_ADC_C__USE_ASM_INIT__
94 1 PrintString1("PWM和ADC测试程序, 输入占空比为 0~256! 输入9999退出\r\n"); //SUART1发送一个字符串
可以看到, .list文件只是给源文件标记上了行号, 其他和源文件相同, 未做任何改变, 注释都还在
.i文件
PrintString1("PWM和ADC测试程序, 输入占空比为 0~256! 输入9999退出\r\n");
display_index = 0;
#line 60 "uart_cmd_test_pwm_as_adc.c" /1
#line 78 "uart_cmd_test_pwm_as_adc.c" /0
AUXR |= (1<<7);
TH0 = ((65536UL -(22118400L / 1000))) / 256, TL0 = ((65536UL -(22118400L / 1000))) % 256;
ET0 = 1;
TR0 = 1;
PrintString1("PWM和ADC测试程序, 输入占空比为 0~256! 输入9999退出\r\n");
AUXR1 &= ~0x30;
可以看到, .i文件是最终生成的源代码文件, 注释, 用宏隔开不需要编译的代码都没了. 将这个文件中的内容, 整理一下, 就是最干净的实现文件.
通过.i文件(预处理文件), 就可以看到最终实现代码有啥区别了
不好使的代码
AUXR = 0x80;
TH0 = (u8)((65536UL -(22118400L / 1000)) / 256);
TL0 = (u8)((65536UL -(22118400L / 1000)) % 256);
ET0 = 1;
TR0 = 1;
好使的代码
AUXR |= (1<<7);
TH0 = ((65536UL -(22118400L / 1000))) / 256, TL0 = ((65536UL -(22118400L / 1000))) % 256;
ET0 = 1;
TR0 = 1;
比较可知:
不好使的代码, 直接给AUXR赋值为0x80, 其实本意是要将AUXR最高位置1, 但是将其他bits都改为了0, 当然其他功能就受影响.
好使的代码, 直接位或AUXR.bit7, 没有动其他bit
一般控制寄存器每个位都有不同的功能, 不能动无关的控制位.
这句不好使的初始化代码, 来自STC的寄存器操作的例程. 在那个例程中, 不受影响, 但是在综合性的集成工程中, 动了无关的控制寄存器的位, 事就来了.
总结
*重构代码时,尽量按照最小化原则去动代码.边改边测试, 如果有问题 , 容易发现一些.
*重构时要有次序,应该后面改的代码,绝不先改.不该现在动的代码绝对不动.
*万一发觉事情不对(那怕只是坏味道),一定先停下来,将当前的问题解决掉.否则积累到后面,积累的越久,问题就越多.
- 手写寄存器操作, 总是不好的. 可以自己用一些好记的宏来代替, 如果官方库中有预定义好的宏, 一定要用.