自己动手焊制硬件开发板

一直有一个做机器人的梦,所以从去年起放弃了十多年的软件开发,开始进入嵌入式领域,先后在.Net Micro Framework 项目中完成了Ti DM335上的GPIOI2CUSB等驱动,方浅浅地了解了什么叫嵌入式开发。

对非软件也非硬件出身的我,学硬件当然从单片入手最简单,如果直接从ARM开始,就像学语言直接从VBVC开始似的,刚开始可能觉得很有成就感,但是学久了,才知道浮在上面很难深下去了。

正好开发USB驱动期间看了一本介绍USB的书,该书还附送PCB板,所以就从焊接这个电路板开始吧(记得最早焊过的相对复杂的电路板是大学金工实习时的收音机,不过和这个相比就是大巫见小巫了)。去了中发电子市场一两次,总算把该买的零件和工具置办齐,现在就要开始动手了(参见下图)。

焊接后的成品(参见下图)

对没有多少焊接经验的我来说,焊接过程即充满波折也充满乐趣。

一开始我很担心,怕焊接时间过长烧坏了芯片,其实这种担心是多余的,一般的芯片还是比较耐高温的,上网查了些资料,说芯片最怕的是静电,所以焊接时一定记得带防静电手腕带。

焊接完毕后,一上电,电源灯正常点亮,可没想到运行ISP程序竟无法下载,用示波器查看,发现主晶振没有起振(也可以用万用表量两管脚电压来判断)。仔细用万用表排查,发现两个问题,一是CPU有几个管脚虚焊,二是串口条线设置有些问题(看原理图理解有误),重新又补焊了CPU的几个管脚和调整了跳线,一上电ISP程序就可以正常下载了,编写了一个小测试程序,果然按钮、LED、蜂鸣器一切正常。

接着测试USB芯片,但是很不妙,读出的ID号为0。又用万用表仔细排查,又是焊接问题,USB芯片一个管脚没有焊好,重新补焊,读ID正常。

看来对我们新手来说,焊接这步很关键,宁愿焊的慢一些,也要焊接的牢一点。

(不过下载了鼠标,U盘等程序,设备还是不能正常运转,用USB分析仪监控了一下,发现设备可以正常接收数据,但是无法向PC返回数据,出现总线超时错误。看来USB芯片还是有些问题,不过这有可能不是焊接的问题了,有可能和时序相关,等有时间再深入研究吧)。

下面是我根据书中和网上的资料重新编写了测试程序:

----------------

STC89C52.h

----------------

#ifndef __STC89C52_H__

#define __STC89C52_H__

#include <REGX52.H>

//--

#define TRUE 1

#define FALSE 0

#define BOOL unsigned char

#define UINT8 unsigned char

#define UINT16 unsigned short int

#define UINT32 unsigned long int

#define UINT64 unsigned long long int

#define INT8 signed char

#define INT16 signed short int

#define INT32 signed long int

#define INT64 signed long long int

//--

#define Fclk 22118400UL   //主频

#define BitRate 9600UL    //串口波特率

//--

void STC89C52_Init(void);

//led 0-7

#define Leds P2

void SetLed(UINT8 led,BOOL ON);

BOOL GetLed(UINT8 led);

//key 0-7

extern volatile UINT8 idata KeyPress,KeyValue;

BOOL GetKey(UINT8 key);

void Delay(UINT16 millisecond);

void Sound(UINT16 millisecond);

void Print(char * info);

void PutHex(UINT32 x,UINT8 Num);         

#endif

---------------------------

STC89C52.c

---------------------------

#include "stc89c52.h"

void Keyboard_Init(void);

void Uart_Init(void);

//--  

void STC89C52_Init(void)

{

   P2=0xFF; //LED全灭

   EA=1;    //允许中断

   Keyboard_Init();

   Uart_Init();

}

//--

void SetLed(UINT8 led,BOOL ON)

{

         if(ON)

         {

             P2 &= ~(0x1<<led);   

         }

         else

         {

             P2 |= 0x1<<led;         

         }

}

BOOL GetLed(UINT8 led)

{

   return ~((P2>>led) & 0x1);

}

//--

volatile UINT8 idata KeyPress,KeyCurrent,KeyOld,KeyNoChangedTime;

void Keyboard_Init(void)

{

   P1 = 0xFF;               //键盘对应的IO设为输入状态

   KeyPress = 0;              //无按键按住

   KeyNoChangedTime = 0;    

   KeyOld=0;

   KeyCurrent=0;

   TMOD &= 0xF0;           //TMOD低四位控制定时器0

   TMOD |= 0x01;           //选择16位定时模式

   ET0 = 1;                //允许定时器0中断

   TR0 = 1;                //启动定时器0

}

//定时器0中断处理

volatile UINT8 idata KeyValue=0;Flag=0,KeyX=0,KeyY=0,KeyXY=0;

code KeyMap[]={0x44,0x81,0x41,0x21,0x11,0x82,0x42,0x22,0x12,0x84,0x24,0x14,0x88,0x48,0x28,0x18};                                    

void Timer0_ISR(void) interrupt 1

{

   UINT8 i;

   //定时

   TH0=(65536-Fclk/1000/12*5+15)/256;

   TL0=(65536-Fclk/1000/12*5+15)%256;

   //开始按键扫描

   KeyCurrent=~P1;

   //按键发生了变化

   if(KeyCurrent != KeyOld)

   {

       KeyNoChangedTime=0;

            KeyOld=KeyCurrent;

            return;

   }

   else

   {

           if(++KeyNoChangedTime>=1) //时间到

           {

         KeyNoChangedTime=1;

                    KeyPress=KeyOld;

           }

   }

  

   //---------------

   switch(Flag)

   {

      case 0:

            P0=0x0F;

             Flag=1;

                   break;

      case 1:

             KeyX=~P0 & 0x0F;   

             if(KeyX != 0x0) Flag=2;

             else KeyXY=0; 

                   break;

           case 2:

             P0=0xF0;

             Flag=3;

                   break;

           case 3:

             KeyY=(~P0 & 0xF0)>>4;

             if(KeyY != 0x0) Flag=4;

                   else KeyXY=0;

                   break;         

           case 4:

              Flag=0;

                    if(KeyXY==0)

                    {

                     KeyXY= KeyY<<4 | KeyX;

           

                            for(i=0;i<16;i++)

                            {

                               if(KeyXY==KeyMap[i])

                               {

                                  KeyValue=i;

                                  break;

                               }

                            }         

                    }

                    break;

         }                                  

}

BOOL GetKey(UINT8 key)

{

   return (BOOL)(KeyPress>>key & 0x1);

}

void Delay(UINT16 millisecond)

{          

   if(millisecond<10)

   {

       UINT8 ms  =(UINT8)millisecond;

            UINT8 num=200;

            while(ms--) while(num--);

   }

   else

   {

      UINT8 num=10;

      while(millisecond--)while(num--); 

   }

}

//--

sfr P4 = 0xE8;

sbit P4_0=P4^0;

void Sound(UINT16 millisecond)

{

     P4_0=0;  

         Delay(millisecond);

    P4_0=1;

}

//--

void Uart_Init(void)

{

   EA=0;                                //暂时关闭中断

   TMOD &=0x0F;            //TMOD低四位控制定时器1

   TMOD |=0x20;                        //自动重装模式

   SCON=0x50;              //串口工作在模式1

   TH1=256-Fclk/(BitRate*12*16);

   TL1=256-Fclk/(BitRate*12*16);

   PCON|=0x80;             //串口波特率加倍

   ES=1;                   //串行中断允许

   TR1=1;                  //启动定时器1

   REN=1;                  //允许接收

   EA=1;                   //允许中断

}

volatile BOOL Sending;

void Uart_ISR(void) interrupt 4

{

   if(RI)  //收到数据

   {

      RI=0;  //清中断

   }

   else

   {

      TI=0;

           Sending=FALSE;  //清正在发送数据

   }

}                                                                                    

 

void PutChar(UINT8 c)

{

    SBUF=c;          //把字符写入发送缓冲区

         Sending=TRUE;

         while(Sending);  //等待发送完毕

}

 

code UINT8 HexTable[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

void PutHex(UINT32 x,UINT8 Num)

{

    INT8 i;

         UINT8 Hexs[9]={'0','\0','\0','\0','\0','0','\0','\0','\0'};

 

         if(Num<1)Num=1;

         if(Num>8)Num=8;                                                                                                         

         for(i=Num-1;i>=0;i--)

         {

            Hexs[i]=HexTable[(x & 0xF)];

            x >>= 4; 

         } 

         Print(Hexs);

}

 

void Print(char * str)

{

   while((*str)!='\0')

   {

      PutChar(*str);

           str++;

   }

}

----------------

main.c

----------------

#include <REGX52.H>

#include "..\common\stc89c52.h" 

void main(void)

{       

  UINT8 i;

  STC89C52_Init();

  //发送信息

  Print("Hello C51!\r\n");

  //蜂鸣器自检

  Sound(200);

  //LED自检

  for(i=0;i<8;i++)

  {

     SetLed(i,TRUE);

          Delay(100);

          SetLed(i,FALSE);

  }  

  while(TRUE)

  {

     Leds=~KeyPress;

          

          if(KeyValue!=0xFF)

          {

                   PutHex(KeyValue,9); Print("\r\n");

             KeyValue=0xFF;

          }

  }

}

其实上面的C51程序很简单,有C功底的人一看就会。不过学ARM却不这么容易了,想在ARM上编写一个最简单的“Hello world!”,就需要做很多初始化工作。做了近一年的.Net Micro Framework porting工作的我,要想实现这一步还真不容易(不过真正学好单片也不容易)。可见站在别人战车上习惯了,自己下来走两步,竟不知道如何举步了。VS2008VS2010等高级开发工具的出现,对我们来说,是福?是祸?我们不难想见。

    十年软件,十年硬件,一步一个脚印,只要努力就有希望!

转载于:https://www.cnblogs.com/yefanqiu/archive/2009/10/26/1590297.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463260.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c/c++整理--c++面向对象(2)

一、看代码写结果——c类成员的访问<span style"font-size:18px;">#include <iostream> using namespace std; #define public private<span style"white-space:pre;"> </span>(1) class Animal { public:<span sty…

.NET MVC异步调用中的Session问题

需要异步处理一个输入问题。以下均代码适用 MVC4controller 代码如下&#xff1a;public class TestController : AsyncController{public async Task<ActionResult> Get1(){await Task.Delay(10000);return Content(DateTime.Now.ToString("HH:mm:ss"));}}在做…

同步与互斥的区别

同步与互斥的区别&#xff1a; 同步&#xff1a;在互斥的基础上实现对资源的有序访问。 互斥&#xff1a;对某一资源在同一个时间只能有一个访问者。 信号量&#xff1a;在互斥的基础上实现对资源的有序访问&#xff0c;是多线程、多进程之间同步的一种方式。

nmcli 命令的基本使用

nmcli 命令的基本使用 nmcli命令 地址配置工具&#xff1a;nmcli nmcli device 查看所有网卡的信息 nmcli device status 和numcli device 相同 nmcli device show 网卡名 查看某个网卡的信息 nmcli connecttion 显示所有网卡的配置连接配置&#xff0c;就是/etc/sys…

人与自然《食虫猎手-下》

讲述了几种动物的捕食方法&#xff0c; 有蝙蝠&#xff0c;鱼&#xff0c;翠鸟&#xff0c;几种动物。没啥感觉&#xff01;转载于:https://www.cnblogs.com/flex_fly/archive/2009/11/06/1597466.html

c/c++整理--c++面向对象(3)

一、与全局对象相比&#xff0c;使用静态数据成员有什么优势优势&#xff1a;&#xff08;1&#xff09;静态数据成员没有进入程序的全局命名空间&#xff0c;因此不存在程序中其他全局命名冲突的可能性。&#xff08;2&#xff09;使用静态数据成员可以隐藏信息。因为静态数据…

超棒的视差滚动效果javascript类库 - Jarallax

为什么80%的码农都做不了架构师&#xff1f;>>> 日期&#xff1a;2012-9-27 来源&#xff1a;GBin1.com 如果你没有听说过视差滚动的话&#xff0c;说明你真out了&#xff0c;作为2011年最流行的网站设计效果之一&#xff0c;给我们留下了深刻的印象&#xff0c;在…

HDFS的特性以及如何保证数据的一致性

链接&#xff1a;https://www.nowcoder.com/questionTerminal/962225fa78e74ba7b1d7d7792407acc6?orderByHotValue1&mutiTagIds629&page1&onlyReferencefalse 主要有以下6点&#xff1a; 1.安全模式&#xff1a; HDFS刚启动时&#xff0c;namenode进入安全模…

Ext js call方法

call 方法 请参阅 应用于&#xff1a;Function 对象 要求 版本 5.5 调用一个对象的一个方法&#xff0c;以另一个对象替换当前对象。 call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 参数 thisObj 可选项。将被用作当前对象的对象。 arg1, arg2, , argN 可选项。将被传递方法参数…

c/c++整理--c++面向对象(4)

一、对静态数据成员的正确描述 下列对静态数据成员的描述中&#xff0c;正确的是 A、静态数据成员可以在类体中进行初始化 B、静态数据成员不可以被类的对象调用 C、静态数据成员不能收private控制符的作用 D、静态数据成员可以直接用类名调用 解析&#xff1a; A错误。静态数据…

PHP 逆转字符串与逆转句子

1 <?php2 #颠倒字符串3 4 #将字符串从头和尾向中间遍历&#xff0c;交换位置5 function cstrrev(&$str, $begin, $len) {6 $i $begin;7 $j $begin $len - 1;8 while ($i < $j) {9 $temp $str[$i]; 10 …

sublime中编译的sass如何改变css输出风格?【这里有答案】

由于在网上找了一遍没找到如果在sublime中将sass编译的css转换成为自己喜欢的风格&#xff0c;所以换了一种思路搜索到了答案&#xff0c;这里我将讲述如果更改。 首先sass总共有四种编译风格 &#xff08;1&#xff09; nested&#xff08;嵌套缩进、默认风格&#xff09; #ma…

关于更改当前公司(一)--ChangeCompany

AX支持多公司帐套&#xff0c;如果一个集团公司有多个分公司&#xff0c;可以通过创建多个公司帐套的方式来实现&#xff0c;在写代码的时候会遇到需要切换公司的时候&#xff0c;AX2009提供了两种方式来实现多公司数据的查询&#xff0c;内置方法ChangeCompany和关键字CrossCo…

c/c++整理--c++面向对象(5)

构造函数的使用 以下代码中的输出语句为0吗&#xff1f;为什么&#xff1f;#include <iostream> using namespace std; struct CLS { int m_i; CLS(int i):m_i(i){ } CLS() { CLS(0); } }; int main() { CLS obj; cout<<obj.m_i<<endl; retur…

西电网络攻防大赛--渗透测试第二题

地址&#xff1a;http://test.xdsec.org/1/ 使用google浏览器打开 点击Resources 找到cookie 发现key 不过也是加密的 猜测是base64加密 so&#xff0c;百度一个解密网站 就直接百度应用了 结果&#xff1a;g0NexTdo0r

非多态的继承情况下,基类指针可以指向派生类对象么?

class Base { // 基类 public:Base(int aa88) : a(aa) {}void f() { // 非virtualcout<<"Base"<<endl;}int a; }; class Derived : public Base { // 派生类 public:Derived(int ba 77, int bb 66) : a(ba), b(bb) {}void f() { // 非多态cout<<…

软件架构阅读笔记(引)

引&#xff1a; 软件架构的目的是发现软件的问题是什么&#xff0c;怎么解决。这些软件遇到的问题往往来自实际项目中。然而作为一个学生的我很少有机会接触实际是项目&#xff0c;所以阅读也是学习的一种方式。从他人的做法中&#xff0c;也可以学习到知识。 各大互联网公司架…

嘗試著去做

昨晚跟叔叔深談許久&#xff0c;得知一熟人開一小型印刷廠&#xff0c;現在需要一套進銷存的管理軟件。對於我本身就從事于這樣的工作崗位&#xff0c;聽及情況后也能明白其中的一些需求。於是決定通過自己的學習來嘗試著去開發一下這樣的軟件&#xff0c;藉助于公司目前使用的…

母函数题目

hdu 1028 Ignatius and the Princess III 母函数模板题 http://acm.hdu.edu.cn/showproblem.php?pid1028 题意&#xff1a; 整数的拆分。 母函数学习http://www.wutianqi.com/?p596 View Code #include <iostream> #include <cstdio> #include <cstring> …

c/c++整理--析构函数

c中虚析构函数的作用是什么&#xff1f;析构函数是为了在对象不被使用后释放它的资源&#xff0c;虚函数是为了实现多态。那么&#xff0c;把析构函数声明为virtual有什么作用呢&#xff1f; 请看下面代码&#xff1a;<span style"font-size:18px;">#include &…