别人的文章:
秘笈:电子电路调试步骤及注意事项
1、反推法
1.1、问题出现
如下代码程序运行效果与个人设计不符
//*********************************************************
#include "SYSCFG.h"
//***********************宏定义****************************
typedef unsigned char u8;
#define Key PA4
//***********************变量定义****************************
static u8 TimeCnt = 0; //记录按下时长,刻10ms
static u8 lock = 0; //lock变量用于判断是否是第一次进行按键确认状态
typedef enum
{
KEY_CHECK = 0, //检测状态
KEY_COMFIRM = 1, //按键确认,已经识别到了前沿抖动
KEY_RELEASE = 2 //按键释放,
}KEY_STATE;
static KeyState =0; // 初始化按键状态为检测状态
static u8 g_KeyFlag = 0; // 按键有效标志,0: 按键值无效; 1:按键值有效
typedef enum
{
NULL_KEY = 0,
SHORT_KEY =1,
LONG_KEY=2
}KEY_TYPE;
static KEY_TYPE g_KeyActionFlag; //用于区别长按和短按
static int shortCnt;
static int longtCnt;
/**
*/
void Key_Scan(void)
{
switch (KeyState)
{
//按键未按下状态,此时判断Key的值
case 0:
if(!Key)
{
KeyState = 1; //如果按键Key值为0,说明按键开始按下,进入下一个状态
}
TimeCnt = 0;
break;
case 1:
if(!Key) //查看当前Key是否还是0,还是就计数加一
{
TimeCnt++;
if(TimeCnt > 61)
{
}
if(TimeCnt > 8)
{
}
}
else // 不还是0,按键释放了
{
KeyState = 2;
TimeCnt = 0; //计数复位
}
break;
case 2:
if(Key) //当前Key值为1,说明按键已经释放,返回开始状态
{
KeyState = 0;
}
break;
default: break;
}
}
/*-------------------------------------------------
* 函数名:interrupt ISR
* 功能: 定时器0的中断处理
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void interrupt ISR(void)
{
static u8 cnt;
if(T0IE && T0IF) //开定时器/计数器0中断&&中断标志置位
{
cnt++;
if(cnt>2) // 每 8.16*n ms执行一次按键扫描程序
{
Key_Scan();
cnt = 0;
}
T0IF = 0; //清零time0中断标志
}
}
/*-------------------------------------------------
* 函数名称: TIMER0_INITIAL
* 功能: 初始化设置定时器0
* 设置TMR0定时时长=(1/系统时钟频率)*指令周期*预分频值*255
* =(1/16000000)*2*256*255=8.16ms
-------------------------------------------------*/
void TIMER0_INITIAL (void)
{
OPTION = 0B00000111;
//Bit5: T0CS Timer0时钟源选择
// 1-外部引脚电平变化T0CKI 0-内部时钟(FOSC/2)
//Bit4: T0CKI引脚触发方式 1-下降沿 0-上升沿
//Bit3: PSA 预分频器分配位 0-Timer0 1-WDT
//Bit[2:0]: PS2 8个预分频比 111 - 1:256
T0IF = 0; //清空T0软件中断
}
//***********************函数声明**************************
void configurate_initial(void); //上电系统初始化
/*-------------------------------------------------
* 函数名:main
* 功能: 主函数
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void main()
{
u8 i=0;
//上电初始化
configurate_initial(); //初始化配置
TIMER0_INITIAL(); //每8.16ms 执行一次按键扫描程序
GIE = 1; //开中断
T0IE = 1; //开定时器/计数器0中断
u8 switch11=0;
// PA7=1;//开启电源
// PC3=1;//开启激光发射器
//上电初始化完毕后
while(1)
{
if(KeyState==1&&TimeCnt > 61) //16ms*61=1s
{
PA7=1;//开启电源
PC3=1;//开启激光发射器
if(i==1)
{
PA7=0;//关闭电源
}
i++;
}
// if(KeyState==1&&TimeCnt > 8) //16ms*8=128ms
// {
// PC3=~PC3;//取反激光发射器的开关
// }
}
}
/*-------------------------------------------------
* 函数名:POWER_INITIAL
* 功能: 上电系统初始化
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void configurate_initial(void)
{
//中断与时钟配置
OSCCON = 0B01110001; //IRCF=111=16MHz/2T=8MHz,0.125us
INTCON = 0; //暂禁止所有中断
PORTA = 0B00000000; //将PA0~7的引脚状态初始为0
PORTC = 0B00000000; //将PC0~7的引脚状态初始为0
OPTION = 0B00001000; //地址OPTION处的Bit3控制看门狗时钟和时钟0的共用分频电路归谁。为1归看门狗,Bit2~0是分频电路的分频系数PS=000
MSCKCON = 0B00000000; //地址MSCKCON处的Bit6->0,禁止PA4,PC5稳压输出; Bit5->0,TIMER2时钟为Fosc; Bit4->0,禁止LVR
CMCON0 = 0B00000111; //关闭比较器,CxIN为数字IO口
//PA4
TRISA = 0B00010000; //地址TRISA处的Bit4=1,表输入
WPUA = 0B00010000; //地址WPUA处的Bit4=1,表开上拉
//PC3
TRISC = 0B00000000; //地址TRISA处的Bit3=0,表输出
WPUC = 0B00001000; //地址WPUA处的Bit3=0,表开上拉
//PA7
TRISA = 0B00000000; //地址TRISA处的Bit7=0,表输出
WPUA = 0B10000000; //地址WPUA处的Bit7=1,表开上拉
}
1.2、减少代码量,使用指示灯PC3
去掉一些代码,希望多按几次按键后引脚PC3可以在示波器上出现上升沿和下降沿。
事实是PC3一直保存高电平
//*********************************************************
#include "SYSCFG.h"
//***********************宏定义****************************
typedef unsigned char u8;
#define Key PA4
//***********************变量定义****************************
static u8 TimeCnt = 0; //记录按下时长,刻10ms
static KeyState =0; // 初始化按键状态为检测状态
/**
*/
void Key_Scan(void)
{
switch (KeyState)
{
//按键未按下状态,此时判断Key的值
case 0:
if(!Key)
{
KeyState = 1; //如果按键Key值为0,说明按键开始按下,进入下一个状态
PC3=1;
}
TimeCnt = 0;
break;
case 1:
if(!Key) //查看当前Key是否还是0,还是就计数加一
{
TimeCnt++;
}
else // 不还是0,按键释放了
{
KeyState = 2;
PC3=0;
TimeCnt = 0; //计数复位
}
break;
case 2:
if(Key) //当前Key值为1,说明按键已经释放,返回开始状态
{
KeyState = 0;
PC3=1;
}
break;
default: break;
}
}
/*-------------------------------------------------
* 函数名:interrupt ISR
* 功能: 定时器0的中断处理
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void interrupt ISR(void)
{
static u8 cnt;
if(T0IE && T0IF) //开定时器/计数器0中断&&中断标志置位
{
cnt++;
if(cnt>2) // 每 8.16*n ms执行一次按键扫描程序
{
Key_Scan();
cnt = 0;
}
T0IF = 0; //清零time0中断标志
}
}
/*-------------------------------------------------
* 函数名称: TIMER0_INITIAL
* 功能: 初始化设置定时器0
* 设置TMR0定时时长=(1/系统时钟频率)*指令周期*预分频值*255
* =(1/16000000)*2*256*255=8.16ms
-------------------------------------------------*/
void TIMER0_INITIAL (void)
{
OPTION = 0B00000111;
//Bit5: T0CS Timer0时钟源选择
// 1-外部引脚电平变化T0CKI 0-内部时钟(FOSC/2)
//Bit4: T0CKI引脚触发方式 1-下降沿 0-上升沿
//Bit3: PSA 预分频器分配位 0-Timer0 1-WDT
//Bit[2:0]: PS2 8个预分频比 111 - 1:256
T0IF = 0; //清空T0软件中断
}
/*-------------------------------------------------
* 函数名:POWER_INITIAL
* 功能: 上电系统初始化
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void configurate_initial(void)
{
//中断与时钟配置
OSCCON = 0B01110001; //IRCF=111=16MHz/2T=8MHz,0.125us
INTCON = 0; //暂禁止所有中断
PORTA = 0B00000000; //将PA0~7的引脚状态初始为0
PORTC = 0B00000000; //将PC0~7的引脚状态初始为0
OPTION = 0B00001000; //地址OPTION处的Bit3控制看门狗时钟和时钟0的共用分频电路归谁。为1归看门狗,Bit2~0是分频电路的分频系数PS=000
MSCKCON = 0B00000000; //地址MSCKCON处的Bit6->0,禁止PA4,PC5稳压输出; Bit5->0,TIMER2时钟为Fosc; Bit4->0,禁止LVR
CMCON0 = 0B00000111; //关闭比较器,CxIN为数字IO口
//PA4
TRISA = 0B00010000; //地址TRISA处的Bit4=1,表输入
WPUA = 0B00010000; //地址WPUA处的Bit4=1,表开上拉
//PC3
TRISC = 0B00000000; //地址TRISA处的Bit3=0,表输出
WPUC = 0B00001000; //地址WPUA处的Bit3=0,表开上拉
//PA7
TRISA = 0B00000000; //地址TRISA处的Bit7=0,表输出
WPUA = 0B10000000; //地址WPUA处的Bit7=1,表开上拉
}
/*-------------------------------------------------
* 函数名:main
* 功能: 主函数
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void main()
{
//上电初始化
configurate_initial(); //初始化配置
TIMER0_INITIAL(); //每8.16ms 执行一次按键扫描程序
GIE = 1; //开中断
T0IE = 1; //开定时器/计数器0中断
PA7=1;//开启电源
PC3=1;//开启激光发射器
//上电初始化完毕后
while(1)
{
}
}
1.3、继续减少代码量
去掉了函数Key_Scan。改成PC3=~PC3;希望可以在示波器上看到方波,每隔8.16ms变换一次电频。
成功输出了:
问题就在函数Key_Scan中。
//*********************************************************
#include "SYSCFG.h"
//***********************宏定义****************************
typedef unsigned char u8;
#define Key PA4
//***********************变量定义****************************
static u8 TimeCnt = 0; //记录按下时长,刻10ms
static KeyState =0; // 初始化按键状态为检测状态
/**
*/
void Key_Scan(void)
{
switch (KeyState)
{
//按键未按下状态,此时判断Key的值
case 0:
if(!Key)
{
KeyState = 1; //如果按键Key值为0,说明按键开始按下,进入下一个状态
PC3=1;
}
TimeCnt = 0;
break;
case 1:
if(!Key) //查看当前Key是否还是0,还是就计数加一
{
TimeCnt++;
}
else // 不还是0,按键释放了
{
KeyState = 2;
PC3=0;
TimeCnt = 0; //计数复位
}
break;
case 2:
if(Key) //当前Key值为1,说明按键已经释放,返回开始状态
{
KeyState = 0;
PC3=1;
}
break;
default: break;
}
}
/*-------------------------------------------------
* 函数名:interrupt ISR
* 功能: 定时器0的中断处理
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void interrupt ISR(void)
{
static u8 cnt;
if(T0IE && T0IF) //开定时器/计数器0中断&&中断标志置位
{
cnt++;
if(cnt>2) // 每 8.16*n ms执行一次按键扫描程序
{
PC3=~PC3;
cnt = 0;
}
T0IF = 0; //清零time0中断标志
}
}
/*-------------------------------------------------
* 函数名称: TIMER0_INITIAL
* 功能: 初始化设置定时器0
* 设置TMR0定时时长=(1/系统时钟频率)*指令周期*预分频值*255
* =(1/16000000)*2*256*255=8.16ms
-------------------------------------------------*/
void TIMER0_INITIAL (void)
{
OPTION = 0B00000111;
//Bit5: T0CS Timer0时钟源选择
// 1-外部引脚电平变化T0CKI 0-内部时钟(FOSC/2)
//Bit4: T0CKI引脚触发方式 1-下降沿 0-上升沿
//Bit3: PSA 预分频器分配位 0-Timer0 1-WDT
//Bit[2:0]: PS2 8个预分频比 111 - 1:256
T0IF = 0; //清空T0软件中断
}
/*-------------------------------------------------
* 函数名:POWER_INITIAL
* 功能: 上电系统初始化
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void configurate_initial(void)
{
//中断与时钟配置
OSCCON = 0B01110001; //IRCF=111=16MHz/2T=8MHz,0.125us
INTCON = 0; //暂禁止所有中断
PORTA = 0B00000000; //将PA0~7的引脚状态初始为0
PORTC = 0B00000000; //将PC0~7的引脚状态初始为0
OPTION = 0B00001000; //地址OPTION处的Bit3控制看门狗时钟和时钟0的共用分频电路归谁。为1归看门狗,Bit2~0是分频电路的分频系数PS=000
MSCKCON = 0B00000000; //地址MSCKCON处的Bit6->0,禁止PA4,PC5稳压输出; Bit5->0,TIMER2时钟为Fosc; Bit4->0,禁止LVR
CMCON0 = 0B00000111; //关闭比较器,CxIN为数字IO口
//PA4
TRISA = 0B00010000; //地址TRISA处的Bit4=1,表输入
WPUA = 0B00010000; //地址WPUA处的Bit4=1,表开上拉
//PC3
TRISC = 0B00000000; //地址TRISA处的Bit3=0,表输出
WPUC = 0B00001000; //地址WPUA处的Bit3=0,表开上拉
//PA7
TRISA = 0B00000000; //地址TRISA处的Bit7=0,表输出
WPUA = 0B10000000; //地址WPUA处的Bit7=1,表开上拉
}
/*-------------------------------------------------
* 函数名:main
* 功能: 主函数
* 输入: 无
* 输出: 无
--------------------------------------------------*/
void main()
{
//上电初始化
configurate_initial(); //初始化配置
TIMER0_INITIAL(); //每8.16ms 执行一次按键扫描程序
GIE = 1; //开中断
T0IE = 1; //开定时器/计数器0中断
PA7=1;//开启电源
PC3=1;//开启激光发射器
//上电初始化完毕后
while(1)
{
}
}
1.4、"事故"位置找到,分析事故现场
1)反推法
中断程序可以按照设定的时间,一次又一次的执行。
中断函数里的Key_Scan函数却不能正常执行。
PC3恒为1,所以PC3=0没有被执行。
PC3=0要执行的话,Key就要等于0。
所以Key一直没有等于0,一直为1。
为什么一直为1?
设计是要Key,即引脚PA4做上拉输入。当按键按下时被拉低为0。
2)祸根
看看PA4的配置
void configurate_initial(void)
{
//中断与时钟配置
OSCCON = 0B01110001; //IRCF=111=16MHz/2T=8MHz,0.125us
INTCON = 0; //暂禁止所有中断
PORTA = 0B00000000; //将PA0~7的引脚状态初始为0
PORTC = 0B00000000; //将PC0~7的引脚状态初始为0
OPTION = 0B00001000; //地址OPTION处的Bit3控制看门狗时钟和时钟0的共用分频电路归谁。为1归看门狗,Bit2~0是分频电路的分频系数PS=000
MSCKCON = 0B00000000; //地址MSCKCON处的Bit6->0,禁止PA4,PC5稳压输出; Bit5->0,TIMER2时钟为Fosc; Bit4->0,禁止LVR
CMCON0 = 0B00000111; //关闭比较器,CxIN为数字IO口
//PA4
TRISA = 0B00010000; //地址TRISA处的Bit4=1,表输入
WPUA = 0B00010000; //地址WPUA处的Bit4=1,表开上拉
//PC3
TRISC = 0B00000000; //地址TRISA处的Bit3=0,表输出
WPUC = 0B00001000; //地址WPUA处的Bit3=0,表开上拉
//PA7
TRISA = 0B00000000; //地址TRISA处的Bit7=0,表输出
WPUA = 0B10000000; //地址WPUA处的Bit7=1,表开上拉
}
可以发现PA4被配置成了关闭上拉的输出。祸根就是它。
2、利用示波器的动态波形
利用示波器,运行程序,观察程序运行在不同阶段时,信号的动态变化。
长按按键:开关机
短按按键:按第1次长亮,
按第2次光强有强到弱,再从弱到强循环。需要中断
按第3次10HZ闪烁
问题:按第3次激光10HZ闪烁几下后,变成长亮?
示波器上看到,按第3次时,出现了占空比逐渐变化的动态波形。非常的直观
据此可以程序逻辑上有问题,按两次的处理程序,在按三次后运行了。
注释渐变程序
按三次,激光正常闪烁了
为什么渐变程序执行了
因为渐变程序在主函数,从按两次的处理程序中断返回,执行的不一定是上图180行的判断,若是渐变程序的182~190,就直接执行了一遍,才去执行180行的判断。
3、溢出造成的奇怪现象
为什么两边不同的代码产生了不同的波形?
努力猜测,解释现象
可以理解为time2计时开始点与time1拉高时间点不一致。
但是为什么不一致?难以猜测解释
我们把time2的延时加长看看。看看补偿上,行不行。
还是这个样子
发现:无论是对高偏短的延长定时,还是对高偏长的缩短定时。波形依旧,则就说明,不是步调的原因,猜测不正确。
time2不是与time1存配合有问题,单独对time2进行测试,看看time2自身的配置是否可以达到效果。
实际定时值为3.5us,与个人设计的500相差极大。
time2配置有问题
PR2是8位,最大值是255
祸根是这个溢出
修改后效果正常了。
4、二分法
将数学的零点类比为祸根:
对于区间[a,b]上连续不断且f(a)·f(b)<0的函数y=f(x),通过不断地把函数f(x)的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法。
5、隔离与定位
5.1 硬件调试
就去查看电路是否可以正常运行,那个地方不能正常运行
1)没有思路
当遇到没有思路时,就要在电路上做改变,无论是改变电池电压,还是把一些线割掉,亦或是把一些器件给焊取下来,就是要做出改变,再去根据新的现象猜测目标问题的原因。
2)隔离与定位
排除思想很重要
6、搜索法
发现程序效果不对时,ctr+f相关变量,看看项目中所有地方的幅值与引用是否正确。
7、细化现象以得到指向
7.1细化使用产品时的异常现象
当出现让人摸不着头脑的现象时,进一步具体化现象,
比如有灯乱闪,要细化成以什么样的频率闪,或者是其他闪烁的特征。
再如:个人人水平仪项目:出现按键H1和V1无法控制激光。
细化1:在推动开机状态,有时会出现按键H1和V1无法控制激光。
————还无法得到指向。
细化2:在推动开机状态,在切换接收模式和非接收模式时,有时会出现按键H1和V1无法控制激光。
————还无法得到指向。
细化3:在推动开机状态,在非接收模式时,短按pow按键调节光强,再切换回到接收模式,不做任何处理,立即返回非接收模式,此时一定会出现按键H1和V1无法控制激光。都是如果立即返回非接收模式后先短按pow按键调节光强,到此POW短按次数为4时,H1和V1又会变得受控。
————可以得到指向:看看代码对上诉步骤都是怎么处理的。
7.2细化产品异常时,软件运行的环境变量,硬件电流电压
7.3有指向可以顺藤摸瓜
POW短按次数为4时,H1和V1又会变得受控
上述句子的4非常有研究价值
8、树形结构的猜想与层层验证
分析问题时:对可能功能实现的硬软件执行流程,树形结构分析,那一块是祸根
软件树形:
9、串口调试
keil调试需要两个特定引脚,串口只需要任意一个引脚
#ifndef __UART_H
#define __UART_H
/****软件串口开始**********************************************/
// 异步收发 接收和发送同时进行互不影响
// 三倍采样率 如9600波特率,定时器中断时间为34.6uS
// 2020-05-27更新1.20版:
// 优化结构体定义
// 优化串口接收部分,接收更稳定正确
// 2019 BY:问星
//********************************************************************
//定义接收和发送的IO口
#define IO_RX RA6 //定义接收的IO口
#define IO_TX RA7 //定义发送的IO口
// sbit IO_RX P2 ^ 1;
// sbit IO_TX P2 ^ 2;
/*
使用方法:
1、定义接收和发送的IO口
//C51
sbit IO_RX P2^1;
sbit IO_TX P2^2;
//PIC
#define IO_RX RC3 //定义接收的IO口
#define IO_TX RC4 //定义发送的IO口
2、在main主程序while(1)循环之前加上串口初始化代码
UART_INIT();
3、设置一个定时器的中断时间为34.6uS,在定时器中断里加上下边的代码
UART_TX();
UART_RX();
4、在main主程序while(1)循环中判断,UART_RX_STA标志是否是RX_DATAOK,如果是则收到新数据,可以处理收到的数据或将数据转存。
if(UART_RX_STA==RX_DATAOK)
{
unsigned char dat;
dat=UART_RX_BUFF; //UART_RX_BUFF里的数据为串口收到的数据
UART_RREST(); //准备接收下一字节数据
}
5、在发送数据前判断UART_TX_STA标志是否是TX_FREE空闲状态,是空闲状态
if(UART_TX_STA==TX_FREE)
{
unsigned char dat;
dat=0xF2;
UART_TDATA(dat); //将dat从串口发送出去
}
*/
//********************************************************************
#define UC8 unsigned char
struct
{
UC8 STA; //接收状态标志 0:空闲;1:开始接收;2:接收完成
//发送状态标志 0:空闲;1:准备发送;2:正在发送;3:发送停止位;0:发送完成
UC8 NUM; //8位单字节接收/发送计数
UC8 CNT; //接收/发送周期计数
UC8 BUFF; //接收/发送缓存变量
} UART_RX, UART_TX;
#define UART_RX_STA UART_RX.STA //接收状态
#define UART_TX_STA UART_TX.STA //发送状态
#define UART_RX_BUFF UART_RX.BUFF //接收缓存
#define UART_TX_BUFF UART_TX.BUFF //发送缓存
#define RX_FREE 0 //接收空闲状态
#define RX_DATAOK 3 //数据接收完成状态
#define TX_FREE 0 //发送空闲状态
//********************************************************************
//串口初始化
#define UART_INIT() \
{ \
IO_TX = 1; \
UART_RX.CNT = 0; \
UART_RX.STA = 0; \
UART_TX.STA = 0; \
}
//********************************************************************
//串口接收
#define UART_RX() \
{ \
switch (UART_RX.STA) \
{ \
case 0: \
{ \
if (IO_RX == 0) \
{ \
UART_RX.CNT++; \
if (UART_RX.CNT == 2) \
{ \
UART_RX.BUFF = 0; \
UART_RX.STA = 1; \
UART_RX.NUM = 8; \
UART_RX.CNT = 0; \
} \
} \
} \
break; \
case 1: \
{ \
UART_RX.CNT++; \
if (UART_RX.CNT == 3) \
{ \
if (IO_RX) \
{ \
UART_RX.BUFF |= 0x80; \
} \
else \
{ \
UART_RX.BUFF &= 0x7F; \
} \
UART_RX.CNT = 0; \
UART_RX.NUM--; \
if (UART_RX.NUM > 0) \
{ \
UART_RX.BUFF >>= 1; \
} \
else \
{ \
UART_RX.STA = 2; \
} \
} \
} \
break; \
case 2: \
{ \
UART_RX.CNT++; \
if (UART_RX.CNT == 3) \
{ \
UART_RX.STA = 3; \
} \
} \
break; \
default: \
break; \
} \
}
//********************************************************************
//准备接收下一数据
#define UART_RREST() \
{ \
UART_RX.STA = 0; \
UART_RX.CNT = 0; \
}
//********************************************************************
//串口发送数据
#define UART_TDATA(data) \
{ \
UART_TX.BUFF = data; \
UART_TX.STA = 1; \
UART_TX.CNT = 0; \
}
//********************************************************************
//串口发送
#define UART_TX() \
{ \
switch (UART_TX.STA) \
{ \
case 0: \
break; \
case 1: \
{ \
UART_TX.CNT++; \
if (UART_TX.CNT == 1) \
{ \
IO_TX = 0; \
} \
else if (UART_TX.CNT == 3) \
{ \
UART_TX.STA = 2; \
UART_TX.CNT = 0; \
UART_TX.NUM = 8; \
} \
} \
break; \
case 2: \
{ \
UART_TX.CNT++; \
if (UART_TX.CNT == 1) \
{ \
IO_TX = UART_TX.BUFF & 0X01; \
UART_TX.BUFF = (UART_TX.BUFF >> 1); \
UART_TX.NUM--; \
} \
else if (UART_TX.CNT == 3) \
{ \
UART_TX.CNT = 0; \
if (UART_TX.NUM == 0) \
{ \
UART_TX.STA = 3; \
} \
} \
} \
break; \
case 3: \
{ \
UART_TX.CNT++; \
if (UART_TX.CNT == 1) \
{ \
IO_TX = 1; \
} \
else if (UART_TX.CNT == 3) \
{ \
UART_TX.STA = 0; \
} \
} \
break; \
default: \
break; \
} \
}
//********************************************************************
/*****软件串口结束*******************************************************/
#endif
10、感觉代码怎么看都是没有问题的
10.1、调用函数——软件断点:while(1);
调用函数存在,函数执行了意料之外的代码。
在可疑的函数后加软件断点:while(1);
10.2、HAL库
没有按照例程的使用规范,找出效果与自己想要的相违背。
好好对比例程,看是否有出入
10.3、想法错误
你实际编程让芯片干的事就是错的
10.4、多进程
多进程交叉运行,多个进程执行的特殊顺序,造成意料之外的效果