打印
[应用相关]

单片机学习中的常见问题

[复制链接]
手机看帖
扫描二维码
随时随地手机跟帖
21
工程师犹饿死|  楼主 | 2021-11-19 23:47 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
打印出i的值为 “1”(基于芯片STC12C5A60S1,11.0592MHZ,其他型号的单品机可能打印出来的效果不同,甚至同样的型号单片机、同样的晶振、同样型号的1602 操作打印出来的值也是不一样的),又变化为:

使用特权

评论回复
22
工程师犹饿死|  楼主 | 2021-11-19 23:47 | 只看该作者
unsigned char i=0 ;/*同时,需要注意这里,修改了类型*/
do{
i++;
}while( ((lcd1602ReadStatus()) & 0x80)  && (i<10));  /*经过验证,10已经可以满足足够的时间了*/

使用特权

评论回复
23
工程师犹饿死|  楼主 | 2021-11-19 23:48 | 只看该作者
这样做才是安全的。(尤其在大系统中,不会因为1602的”不存在“导致整个系统的运行失败,经典案例如下)

(在2015年2月7日,我帮助一个大四学生调试毕设时,也发现了同样的问题,此同学在1602液晶屏的写命令、写数据函数里面加入了判忙函数,判忙核心代码如下:

do{
;
}while( (lcd1602ReadStatus()) & 0x80));

使用特权

评论回复
24
工程师犹饿死|  楼主 | 2021-11-19 23:49 | 只看该作者
,最后因在系统设计时,暂时用了1602显示,后来为了做上位机,就用了串口通信代替1602, 拔掉了1602液晶屏,但是没有屏蔽掉主函数中关于1602的操作,导致了程序卡死在判忙函数中,因为如果没有硬件连接,通过数据口读取到的1602状态数据是0xff,然后0xff&0x80,这样得到的结果永远是1(除非再次插上液晶屏或者手动将数据最高bit对应的IO口拉低),导致程序卡死在这里,而且这些功能都是封装好的,所以就更加加大了难度,导致一周没有调试出来,后来,我给他指出两种方法(1)在主函数中屏蔽所有关于1602液晶屏的函数,实验后,系统运行正常(2)修改判忙函数,因为一劳永逸,试验后,运行正常,即使主函数中没有屏蔽1602相关函数,1602硬件暂时取下,也是可以成功运行的)

使用特权

评论回复
25
工程师犹饿死|  楼主 | 2021-11-19 23:50 | 只看该作者
另外,还有很多同**用了延时的方法去操作,似乎大部分人都得到了满意的结果,那么,这里有出现了两个问题:(1)延时的结果有三种:延时太小、延时正好、延时太大,对于大家来说,延时正好、延时太大都是可以完成系统的设计的,但是,你又如何保证你的延时不会小呢?大部分人想,这非常简单,把延时设计的非常大就好了,那么,就引出了问题(2)延时太大,不利于系统整体设计,导致了效率太低 。 何去何从,大家可以想一想。

使用特权

评论回复
26
工程师犹饿死|  楼主 | 2021-11-19 23:50 | 只看该作者
问题0008:调试程序之“穷途末路”
有时候,在调试程序时,明明都是严格按照datasheet的说明和时序图编写的代码,就是没有效果,然后借鉴别人的代码,代码相同,但还是没有效果 。 这时候,先要怀疑硬件,如果硬件没有问题,有可能还会有一个原因,那就是单片机的问题(或者是keil软件的问题,这个不得而知了)。我之前遇到过编写一个代码,没有效果,最后把全部代码屏蔽掉,只在main函数中,点亮了LED,但还是失败了,后来,复制代码,重新新建工程,粘贴代码,就好了。(这里不是喷STC,其实STC在国内做的较好,但是总会有一些奇葩的时候),这里分享一下,仅个人经历。

使用特权

评论回复
27
工程师犹饿死|  楼主 | 2021-11-19 23:51 | 只看该作者
问题0009:如何一步步测试编写代码

单片机程序测试调试似乎对于刚入门的同学有一定难度,但是入门之后我们快速调试程序呢?很多人写代码一气呵成,然后在main函数中调用10几个子函数,然后直接通过液晶屏或者其他的手段观察效果是正确,这样的方法对吗 ?以下是常用方法:

使用特权

评论回复
28
工程师犹饿死|  楼主 | 2021-11-19 23:52 | 只看该作者
   1.借助于网上的视频讲解或源代码,(对于32位的MCU尚可理解,但是51、PIC.MSP430单片机使用者如果入门后还是同样的方法,你就OUT了),但只适用于部分网上资料较多的芯片。

使用特权

评论回复
29
工程师犹饿死|  楼主 | 2021-11-19 23:52 | 只看该作者
2.借助"逻辑分析仪"仪器去分析(这种神器我也是通过网上资料介绍,有所了解,但是并没有使用过,不过好像非常好用的),通过逻辑分析仪可以分析我们的时序是否存在问题,但是个人感觉比较适用于菜鸟和**单片机程序的高手,对于大多数用户,没有必须花钱购买

使用特权

评论回复
30
工程师犹饿死|  楼主 | 2021-11-19 23:53 | 只看该作者
3.利用程序本身去验证程序,编写一个函数,测试一个函数,操作简单,屡试不爽,这里以大家熟知的51类单片机STC12C5A60S2和数字温度传感器DS18B20为例(单总线协议通信)。

使用特权

评论回复
31
工程师犹饿死|  楼主 | 2021-11-19 23:53 | 只看该作者
下图为DS18B20的“复位”时序,因为每次操作都需要MCU发送一个复位信号,所以,“复位”函数相当重要。

使用特权

评论回复
32
工程师犹饿死|  楼主 | 2021-11-19 23:54 | 只看该作者

使用特权

评论回复
33
工程师犹饿死|  楼主 | 2021-11-19 23:55 | 只看该作者
我们知道,当DS18B20存在时,红色部分的时间内,总线将会被DS15B20拉低,呈现低电平   ; 如果DS15B20不存在,则在单片机使用总线(蓝色)后,红色部分仍然是高电平。

使用特权

评论回复
34
工程师犹饿死|  楼主 | 2021-11-19 23:56 | 只看该作者
假设我们有以下定义:
typedef unsigned char UB8 ;
typedef unsigned short int UW16 ;
typedef unsigned long UL32 ;

typedef char SB8;
typedef short int SW16 ;
typedef long SL32 ;
       
#define HIGH_LEVEL 1       
#define LOW_LEVEL  0

sbit ds18b20_io_bit        = P1^7 ;/*根据硬件选择*/

#define DS18B20_EXISTENCE                        0 /*存在DS18B20*/
#define DS18B20_NOT_EXISTENCE                -1/*不存在DS18B20*/

使用特权

评论回复
35
工程师犹饿死|  楼主 | 2021-11-19 23:56 | 只看该作者
然后编写“复位函数”

/******************************************************
Function        :ds18b20Init
Input                :N/A
Output                :N/A
Return                :DS18B20_EXISTENCE或者DS18B20_NOT_EXISTENCE
Description        :N/A
Note                :经过测试在11.0592MHZ和12.00MHZ条件下都可以
                        检测到ds18b20的存在。
******************************************************/
SB8 ds18b20Init(void)
{

        SB8 existenceFlag ;
        UB8 i=0 ;
       
        ds18b20_io_bit = HIGH_LEVEL ;
        _nop_() ;
        _nop_() ;       

        /*master transmit the reset pulse */
        ds18b20_io_bit = LOW_LEVEL ;
        delay720usForDs18b20();

        /*rising edge*/
        ds18b20_io_bit = HIGH_LEVEL ;

        /*ds18b20 wait 15us to 60us then transmit a presence pulse by
        pulling the 1-wire low for 60us to 240 us */

        delay15usForDs18b20();
        delay15usForDs18b20();
        delay15usForDs18b20();
        delay15usForDs18b20();

       
        if( ! ds18b20_io_bit)
        {/*ds18b20 eixstence*/
                existenceFlag = DS18B20_EXISTENCE;
        }
        else
        {/*no ds18b20*/       
                existenceFlag = DS18B20_NOT_EXISTENCE;                          
        }

        while((!ds18b20_io_bit) && (i<250))
        {
                i++;/*wait*//*暂时,具体见调试*/
                /*经过测试,这里的250对于11.0592MHZ和12MHZ都远远足够了*/
        }

        return existenceFlag ;
}

使用特权

评论回复
36
工程师犹饿死|  楼主 | 2021-11-19 23:57 | 只看该作者
然后,我们验证此函数是否可以成功完成“复位功能”:(时序不再详细分析)
#include <reg52.h>
#include "ds18b20.h"


void main(void)
{
        SB8 flag = -3 ;

        P1=0x00;//连接leds,高电平点亮
       
        flag = ds18b20Init();

                if( flag == DS18B20_EXISTENCE) //检测结果:存在,0
                {
                        P1 = 0x01 ;
                }
                else if(flag == DS18B20_NOT_EXISTENCE)//检测结果:<span style="font-family: Arial, Helvetica, sans-serif;">不存在,-1</span>
                {
                        P1=0x02;
                }
                else
                {
                        P1 = 0x04 ;
                }
                while(1) ;
}

使用特权

评论回复
37
工程师犹饿死|  楼主 | 2021-11-19 23:58 | 只看该作者
这样,我们通过LED就可以验证函数了:
       (1)正常连接DS18B20,结果如果是P1的第一个灯亮了(P1=0x01),则表示单片机可以检测到DS18B20的存在,说明函数可能对了(可以检测到DS18B20的存在);

使用特权

评论回复
38
工程师犹饿死|  楼主 | 2021-11-19 23:59 | 只看该作者
(2)拔掉DS18B20,结果如果是P1的第二个灯亮了(P1=0x02),则表示单片机未检测到DS18B20的存在,说明函数完全正确。(可以同时检测到DS18B20的存在和不存在)

使用特权

评论回复
39
aoyi| | 2021-12-11 09:16 | 只看该作者
这个还是dip封装的那种的吧

使用特权

评论回复
40
wiba| | 2021-12-11 09:17 | 只看该作者
我觉得第一条可以忽略了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则