tag 标签: 凤舞天

相关帖子
相关博文
  • 热度 30
    2014-8-19 16:31
    1494 次阅读|
    6 个评论
            说到移动微平台,我们就不得不提MTK山寨手机在深圳的一个发展历程。2006年是山寨机市场最火爆的一年,这一年也同样是台湾联发科的手机方案高速发展的一个时期。与此同时深圳一家新注册的手机设计公司华禹高科技有限公司正式成立,这家公司也就是目前在便携式行业终端市场上做得风声水起的深圳华禹工控科技有限公司的前身。2008年在山寨机市场到达顶峰的时候,华禹高科技有限公司激流勇退,成立行业应用设计团队,集中精力,专门从事便携式行业终端包括手持PDA。         手机作为消费类电子产品中迭代速度最快的一个快消品,所有最先进的硬件、软件、工艺、生产、加工技术多在这个领域得到了充分的展示。可以毫不夸张的说,手机这个小小的掌上设备汇聚了同时代全球最领先的半导体技术的发展。华禹高作为一个先知先觉者,早早意识到了手持行业终端存在的巨大商机,于是迅速的带着手机领域的先进技术切入到了行业应用市场。携带着手机领域的巨大优势,在成功的设计了北京公交一卡通的手持刷卡设备以及上海世博会入园检票设备后,发现了手持行业终端领域存在非常多变的行业需求,而且基本上都是项目型的为主。         在实际的工程开发过程中,发现所有现代的行业设备终端的90%以上的工作在于主控系统的开发,其中包含了系统平台构建、界面显示、数据传输、用户输入等,而只有10%的开发工作量在于传感器数据采集方面的工作。那么有没有一种比较好设计思路可以满足XP极限开发模式,可以加快产品问世的进度。这其中有两种方式可以选择:        1)主板设计和外观设计由设计方案公司提供,并且在主板上面预留出固定空间用于和客户数据采集模块,客户可以不用关心结构设计,只需要关注数据采集模块设计就可以了。        2)方案设计公司提供核心模块,客户自行设计外观,客户基于核心模块的引脚来设计外观和主板。         在经过两种方式的设计思路实际实施的过程中,我们发现核心模块的方式更加容易为客户提供比较完美的解决方案。通过采用核心模块的方式,华禹工控设计了国内首款手持机开发板P1300,并且配套了国内首本手持机的开发书籍。P1300的大获成功,核心模块的思路由此确立。         但是这个时候另外一个问题又出现了由于客户采用核心模块自行订制方案,导致软件方面的支持非常的不方便,软件的版本维护也变得非常的不方便和混乱。在这个过程中,公司总经理王绍伟在中国电子科技大学的教授的一次交谈过程中,提到了统一的概念,通过将软件统一化和硬件的核心模块化,并在行业层面上,以统一的概念为基础提出了移动微平台的概念。这一年是2009年,也可以称之为移动微平台元年。自此之后,华禹工控一直延续着这样的一种移动微平台理念,不断地扩展新的产品平台,从最早的联发科的山寨手机方案到三星的wince方案,从三星的wince方案到最新的android方案,他们一直坚持在自己的理念,并不断前进。         移动微平台已经走过了7个春秋,脚下的路究竟会通向何方,让我们拭目以待,我们期待会有一个更好的未来!  
  • 热度 26
    2014-7-21 10:37
    1244 次阅读|
    2 个评论
             自从上任总经理凤舞天手中接过企业经营的接力棒到现在为止,已经大约2年了。回想自己走过的这一段路,其中的挫败感很强,究其原因,一方面限于自身的能力,另外一方面限于自身眼界和经历。所以在此借助这样一个讲故事的方式,和各位分享下自己的故事,希望各位可以引以为戒。          我要讲的故事应该是从2012年的7月份开始的。当时公司的业务方向,因为原公司总经理凤舞天正在开拓新的业务方向,由于精力有限无法兼顾两项业务,在加上公司一直重视的总经理轮换制度,所以我第一次同开始正式接手公司的经营。因为第一次正式开始考虑经营的问题,加上我个人也是从软件研发的身份突然转变为总经理,所以一开始的想法比较简单就是萧规曹随。并没有特别明确的经营思路。所以公司基本上也就没有了新官上任三把火的经营定调过程。因为公司的原有产品在当时销售还算稳定,主要矛盾就是新产品推出没有,所以唯一明确的就是公司需要推陈出新,一个是android核心板AP7700,另外一个就是android手持机PE900于是开始提上日程,计划能够在第二年的五月份正式上市。            公司当时共有30来个人,外观方面没有ID工程师,只有结构工程师.于是从当年9月底开始正式启动ID设计,同时伴随着android开发板的启动,时间一直持续到12月份.在这个推动的过程中,开发板的开发工程师和结构工程师端分别出现了问题.如果从结果的导向来看,这样的结果似乎都是他们能力不足造成的.但是今天如果回头来看的话,其根本原因是我在其中的职责缺位造成的.由于我自身硬件水平不足,以及对磨具结构的粗浅认识.使得我在依赖他们来设计能力的时候,同时又没有办法指导他们的设计达到自己的要求.导致自己在其中只是执行了一个作为项目经理一样的安排者的角色,没有在其中做到进行良好沟通以及学习判断的能力.另外因缺乏对公司工程师的个人能力以及性格充分的了解,导致了研发效率的急剧降低.所以作为微小企业经营者的一个首要条件,必须具备全面的技能以及对公司的每一个人员要有充分的认识.          在2013年初,公司接到一个车载平板的开发合同.因为这个项目是有钱会进入公司.所以在安排项目的顺序的时候,将平板项目排在了首位,而将自己的android手持机PE900排在了后面.另外因为担心会重蹈去年的项目的错误,指定相对稳重的工程师,并将其中的外观结构部分的设计外包给专业的设计公司.此项目基本上得以顺利进行.然而公司的下一代打产品android手持机PE900却再次跳票.感觉不对,于是又回头加快PE900的进度.由于前期的设计理念不是特别的清晰,导致我们设计工作出现了反复.回头来看,一个总经理对公司的重要目标一旦失去聚焦,会产生捡了芝麻丢西瓜的结果.最终在10月份,公司才终于推出PE900产品.虽然我们的产品具备相当的优势,但是这个时候,Android手持机销售旺季已经错过.这个时候,公司的产品销售成为了公司的主要矛盾.         当一个主要矛盾解决的时候,另外一个相对次要的矛盾又摆在了首位.华禹工控从创立之初开始,是一个以技术实力起家的公司.公司没有专门的销售团队,而是依靠公司的创始人凤舞天的网络营销而不断获得客户认可,获取订单的一种销售模式.凤舞天技术、感悟,用打动人心的高质量的内容吸引了大量的关注,而博客给凤舞天带来许多读博客认可他的人品、理念而主动找到他来谈合作、下订货的客户甚至朋友.在我接手公司运营后,基本上没有朝着这方面做,一方面是因为没有足够强大的自信,二是功利性太强.所以导致公司经营上的失误.对于为这些失误买单的同事以及因为我们产品推迟造成商机推迟的客户,在这里向各位真诚的道歉.          人生总要为这些不断出现的问题付出些代价.我是个普通人,有一颗积极的心,仅此而已.我需要一个深度的潜意识的转变,今天的这么些絮絮叨叨就作为一段见证的开始吧.
  • 热度 40
    2013-9-4 16:55
    2226 次阅读|
    5 个评论
         一般转换都是用数组,结构体及指针,这样是便于以后函数操作。灵活的运用宏定义,编程更加简洁。 举例消息处理方法应用:     如下的定义为在处理消息时候用到很方便,把消息类型和消息值最后封装在一起。 灵活的处理了Uint和Byte 之间转换。   #define UintToByte3(data)               ((byte *)((data))) #define UintToByte2(data)               ((byte *)((data))) #define UintToByte1(data)               ((byte *)((data))) #define UintToByte0(data)               ((byte *)((data))) #define UintToUshort1(data)             ((ushort *)((data))) #define UintToUshort0(data)             ((ushort *)((data))) #define GetMessageType(data)            UintToByte3(data)  #define GetMessageData(data)            (data 0x00FFFFFF) 消息封装处理函数: void PostMessageToLogicTask(MessageType messageType, uint data) {     bool postMessage;     if (messageType != TimerMessageType)     {         UintToByte3(data) = messageType;     }         postMessage = System.Os.PostMessageQueue(System.Device.MessageQueuePoint, (void *)data);      Assert(postMessage); } 特别说明: MessageType 是枚举型,定义的值为Byte 类型 。详细定义为如下 typedef enum {     KeyMessageType      = 0xFF,         UartMessgeType      = 0xFE,       TimerMessageType    = 0xF0  }MessageType;   更巧妙的定义,大家一起帮忙分析为什么可以这样定义,用引号来美化编程界面。 Menu.WorkForm.BackTextPoint = "频率          Hz功率   %       W电压    电流    温度   C        ";       App.Menu.WorkForm.BackTextPoint =                                       "频率          Hz"                                       "功率   %       W"                                       "电压    电流    "                                       "温度   C        "; 上面二种定义为啥功能一样。欢迎各位探讨。 typedef struct {     const byte* BackTextPoint;     Chart     * ChartPoint;     Label     * LabelPoint;     TextBox   * TextBoxPoint;     void      * FocusTextBoxDataPoint; }Form; 欢迎各位与我一起学习ARM 技术,我的E-MIAL:timeisours@163.com,web:www.51buddy.com,QQ:158377757  
  • 热度 22
    2013-9-4 14:57
    1623 次阅读|
    3 个评论
             指针实际上只是一个寄存器,只保存指向内存的地址非实际需要的数值。一般使用它都是需要有一个实际保存内容的变量,一般是用结构体,使用指针主要是方便操作,如下Key 键值读取,直接操作寄存器地址,同时运用宏定义,简化使用。         msOS 通过扫描方式实现了矩阵键盘值读取同时也实现了长按与短按键功能,通过注册函数KeySystemTickService 来收集与检测按键信息供其他函数使用。         按键实现机理,从原理图来分析,原理图设计已经做了特如处理,按键处接了vdd3.3V 和 电阻 1K,默认状况是接按键 的5个IO口都是低电平,若是有按键按下,其中相应的IO口为输入高电平。         扫描函数(ScandPin)中通过改变了行按键 输出值, (ScandPin01 = 0;ScandPin00 = 1),通过判断列的IO口状况,输出自己定义的按键值。            长按与短按及去抖动实现原理:是在 KeySystemTickService 函数中进行计数 ScandCounter 及 JitterCounter,此函数被SysTick_Handler 函数调用,sysTick 为系统CPU 节拍时钟,即所谓心跳函数。每隔100个tick 进行运行一次KeySystemTickService 函数。 一个Tick 时间由如下函数得到  SysTick_Config(SystemCoreClock / 10000);长按短按判断依据是在每执行一次KeySystemTickService 函数时候,若是有按键之后读到的值为invalid,JitterCounter--,去抖动,若是无松开则ScandCounter++,判断第二次值是否一样,若是不一样丢掉按键信息即是去抖原理,一样按键值,ScandCounter++ 继续增加,当超过设定的最长按键时间(ScandCounter = LongInterval)之后抛出按键消息。     精彩绝妙的宏定义及指针使用,直接操作寄存器。 //IO口操作,只对单一的IO口!确保n的值小于16! #define BIT_BAND(addr, bitnum) ((addr 0xF0000000)+0x2000000+((addr 0xFFFFF)5)+(bitnum2)) #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) #define BIT_ADDR(addr, bitnum)   MEM_ADDR(BIT_BAND(addr, bitnum)) #define PaIn(n)    BIT_ADDR(GPIOA_IDR_ADDR,n) #define PaOut(n)   BIT_ADDR(GPIOA_ODR_ADDR,n) #define PbIn(n)    BIT_ADDR(GPIOB_IDR_ADDR,n) #define PbOut(n)   BIT_ADDR(GPIOB_ODR_ADDR,n) #define ScandPin00 PbOut(4) #define ScandPin01 PbOut(5) #define ScandPin10 PcIn(10) #define ScandPin11 PcIn(11) #define ScandPin12 PcIn(12) #define ScandPin13 PbIn(3) #define ShortInterval   3  /*短按按键间隔*/ #define LongInterval    40  /*长按按键间隔*/ #define JitterInterval  10  /*防误动按键间隔*/ 详细操作函数如下:(函数名字很直观表达函数内容) static byte RemapKey(byte scandValue) //重新定义短按键键值 {     switch(scandValue)     {         case 0xEF:             return(0);         case 0xDF:             return(1);        。。。         default:             return(invalid);     } } static byte RemapLongKey(byte scandValue) //重新定义长按键键值 {     switch(scandValue)     {         case 0xEF:             return(0x30);         case 0xDF:         。。。         default:             return(invalid);     }  }   static byte ScandPin(void) // 扫描方式检测按键 {     byte scandValue;       scandValue = invalid;     if(ScandPin13 == 0)         scandValue = 0x7F;     if(ScandPin12 == 0)         scandValue = 0xBF;     if(ScandPin11 == 0)         scandValue = 0xDF;     if(ScandPin10 == 0)         scandValue = 0xEF;     ScandPin00 = 0;     ScandPin01 = 1;       DelayUs(1);     if(ScandPin13 == 0)         scandValue = 0xF7;     if(ScandPin12 == 0)         scandValue = 0xFB;     if(ScandPin11 == 0)         scandValue = 0xFD;     if(ScandPin10 == 0)         scandValue = 0xFE;     ScandPin01 = 0;     ScandPin00 = 1;     return(scandValue); } void KeySystemTickService(void) // 注册机制,检测是否有按键,发送KeyMessageType 类型的PostMessageQueue 消息。 {     byte scandValue;     scandValue = ScandPin();    ....                 if (ScandCounter == LongInterval)         {             PostMessageToLogicTask(KeyMessageType, RemapLongKey(ScandValueSave));                    }         else if (ScandCounter ShortInterval)         {             PostMessageToLogicTask(KeyMessageType, RemapKey(ScandValueSave));         }         ScandCounter = 0;         ScandValueSave = invalid;         JitterCounter = JitterInterval;  }     ..... } void SysTick_Handler(void) {     static unsigned char Counter = 0;     。。。。     switch(Counter)     {      。。。。。。         case 15:             SystemTick100RegisterPointBlock ();             break;                      case 97:             RtcSystemTickService();             break;         case 99:             KeySystemTickService();             break;         default:             break;     }     AdcSystemTickService(); // System.Device.Io.SetBeep(true);  CheckstationSystemTickService(); }   硬件图如下: 欢迎各位与我一起学习ARM 技术,我的E-MIAL:timeisours@163.com,web:www.51buddy.com,QQ:158377757
  • 热度 37
    2013-9-2 10:47
    2578 次阅读|
    12 个评论
    人机交互(Human-Computer Interaction, 简写HCI):是指人与计算机之间使用某种对话语言,以一定的交互方式,为完成确定任务的人与计算机之间的信息交换过程。       从上面的定义,可能太抽象化了,用生活中的例子来说,假如你要吃水煮鱼,选择不同功能电磁炉,人的劳累程度不一样。怎么样才可以做出色香俱全的菜肴,不同电磁炉提供的交互方法不同,有些电磁炉可以通过设定长时间低功率把鱼和其他配料味道炖在一起, 有些只能调整功率,也是可以做出美味的,有些一键设置模式,按普遍规律固定方法煮鱼。 以上其实就是三种不同人机交互方式来完成相同功能,各有不同市场需求。   今天把我学习理解到的 msOS GUI 设计跟大家分享。 msOS 灵活运用结构体,仿C# 的风格,轻便的设计出在硬件 JN12864J LCD上可交互的显示GUI, 设计思想是按添加组件方法,灵活的处理多界面,不同数据类型显示及参数调整。采用面向对象及链表方式设计方式如 Form、Label及TextBox等控件,让图形界面设计非常简单而让设计者只关心业务逻辑设计。   具体见如下框图。 链 表方式: 详细见如下函数 typedef struct LabelSelf {     byte X;   // display information at X'row location,it's only 4 row.     byte Y;   //display information at Y'column location     byte Shift; //     int Offset;     DataType Type;     DataAlign Align;     void * DataPoint;     const string * StringBlockPoint;     struct LabelSelf * NextLabelPoint;//链表 }Label; 界面设计:mmi.c 文件,通过注册控件方式,比如一个界面就是一个Form,一个form 由Label 及TextBox 及 BackText 构成。其中BackText 为固定内容,动态数据由Label 及TextBox 来控制。   目前程序做了5个Form  Logo、check,work,setup,service。拿一个最简单的Form 来分析。     System.Gui.Form.Initialize(App.Menu.CheckForm);// 即一个LCD 界面,目前只是显示三个三角形,可以编写 实现自己公司的LOGO.     CheckChart.Character = '*';     for(i = 0; i 16; i++)     {         CheckChart.Column = 0;     }     App.Menu.CheckForm.ChartPoint = CheckChart;   业务逻辑部分已经包含到控件的结构体定义中去,我们只要编写函数改变控件中相应变量,相对应的分层文件为data.c void InitializeData(void) {     App.Data.Frequence = 980000;     App.Data.Power = 6000;     App.Data.PowerPercent = 12;     App.Data.Voltage = 99;     App.Data.Current = 101;     App.Data.Temperature = -25;     App.Data.State = 1;     App.Data.MaxPower = 6000;     App.Data.MaxTemperature = 50;     App.Data.MaxFrequence = 980000;     App.Data.MaxFrequenceOffset = 100000;     App.Data.MinStream = 50;     App.Data.SerialNumber = 0;     App.Data.ProductionDate = (13 16) + (7 8) + 24;     App.Data.IdentifyNumber0 = 0x12345678;     App.Data.IdentifyNumber1 = 0x34567890;     App.Data.IdentifyNumber2 = 0x56789012;     App.Data.IdentifyNumber3 = 0x78901234; } 备注:GUi.c 中的一些函数设置很巧妙,必须要结合硬件驱动,这里驱动更加巧妙。 几个关键点如下: GUi.c 如下函数设计来源硬件驱动及硬件功能。 static char GuiBuffer ;//用于交换显示的数据结构,显示4行16个字符。 static char DisplayBuffer ; //64×16 位字符显示 RAM(DDRAM 最多 16 字符×4 行,LCD 显示范围 16×2 行)   硬件驱动基础函数: static void LcdSendData(byte data)// 写数据 static void LcdSendInstruct(byte instruct)// 写指令   封装函数 static void LcdDisplayString(byte y, string string)   最后是通过DisplayString来调用封装函数。  System.Device.Lcd.DisplayString = LcdDisplayString; DisplayString 函数是通过GUI.C 中的Updata 函数来更新显示数据。 static void Update(void) {     byte i, j;     bool update;             for (i = 0; i 4; i++)  {         update = false;         for (j = 0; j 16; j++)         {             if(DisplayBuffer != GuiBuffer )             {                 DisplayBuffer = GuiBuffer ;                 update = true;             }         }         if(update == true)         {             System.Device.Lcd.DisplayString(i, DisplayBuffer );         }         else         {             DelayMs(1);         }     } }   硬件驱动设计跟硬件相关的几点理解: const char Array = {     0x80, 0x90, 0x88, 0x98 }; //来源于手册如下描述, DDRAM 行地址。 variable = 0x00F80000 | ((instruct 0xF0) 8) |((instruct 0x0F) 4);  variable = 0x00FA0000 | ((data 0xF0) 8) |((data 0x0F) 4); // 来源于SPI 时序, 上述就是组合出一次通信需要传输24BIT。