EDN首页   博客首页

最新日志

发表于:2008-12-23 21:09:06
标签:液晶驱动  

0

液晶模块LCM046的驱动程序

    LCM046是一款4位段码液晶模块。这儿列出的驱动是针对mega168微控制器的。具体的管脚连接可以参考.c文件。驱动包括两个文件,.c和.h文件,分别罗列如下:

.h

/********************************************************************************
 * Litlle Humidity&Temp Module
 * Copyright (c) 2008 bpesun <bpesun@163.com>
 * All rights reserved.
 * V0.1
********************************************************************************
  文件: lcm046.h
  说明: lcm046的驱动头文件
  原理:
  编写者: bpesun@163.com
  版本控制:
 ----------------------------------------------------------------------------
 版本号  日期  修改内容        修改者
 ----------------------------------------------------------------------------
 1.0     2008.12.12  初稿            bpesun                              
 ----------------------------------------------------------------------------
********************************************************************************/


#ifndef _LCM046_H
#define _LCM046_H

/* ----------------------- Platform includes --------------------------------*/

#include <avr/io.h>
#include <avr/interrupt.h>

/* ----------------------- Defines ------------------------------------------*/


/* ----------------------- Function prototypes ------------------------------*/
void vLCM046Init(void);
void vLCM046WriteCommand( unsigned int usCommand );
void vLCM046WriteData( unsigned char ucAddr, unsigned char ucData );
void vLCM046BitDisplay( unsigned char ucBit, unsigned char ucData );

#endif

.c

/*
 * little Humidit&Temp Module
 * Copyright (c) 2008 bpesun <bpesun@163.com>
 * All rights reserved.
 * V0.1
 */
/********************************************************************************
  文件: lcm046.c
  说明: 模块驱动
  原理:
  编写者: bpesun@163.com
  版本控制:
 ----------------------------------------------------------------------------
 版本号  日期  修改内容        修改者
 ----------------------------------------------------------------------------
 1.0     2008.12.12  初稿            bpesun

 ----------------------------------------------------------------------------
********************************************************************************/


/* ----------------------- System includes ----------------------------------*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#include <math.h>
#include <avr/wdt.h>

/* ----------------------- Platform includes --------------------------------*/
#include "lcm046.h"

/* ----------------------- project includes ----------------------------------* /


/* ----------------------- Defines ------------------------------------------*/
/*1-/CS---PC0
2-/RD-----PC1
3-/WR-----PC2
4-DA------PC3
5-GND-----PC4
6-VLCD----PC5
7-VDD-----PC6
*/
#define INIT_LCM( )   DDRC="0xFF";PORTC|=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3)|(1<<PC5)|(1<<PC6);PORTC&=~(1<<PC4)
#define LCM_CLK(i)    if (i) PORTC|=(1<<PC2); else PORTC &= ~(1<<PC2)
#define LCM_CS(i)     if (i) PORTC|=(1<<PC0); else PORTC &= ~(1<<PC0)
#define LCM_DATA(i)   if (i) PORTC|=(1<<PC3); else PORTC &= ~(1<<PB3)

#define LCM_COMMAND_INIT   0x29
#define LCM_COMMAND_RC     0x18
#define LCM_COMMAND_RC_ON  0x01
#define LCM_COMMAND_LCD_ON 0x03

#define MAX_BIT  4


/* ----------------------- Type definitions ---------------------------------*/


/* ----------------------- Static variables ---------------------------------*/
const unsigned char ucNumTrueValueTable[11]=  //断码的真值表
{//       DCGB*EFA
  0xD7,// 11010111  0
  0x50,// 01010000  1
  0xB5,// 10110101  2
  0xF1,// 11110001  3
  0x72,// 01110010  4
  0xE3,// 11100011  5
  0xE7,// 11100111  6
  0x51,// 01010001  7
  0xF7,// 11110111  8
  0xF3, //11110011  9
  0x00  //00000000  什么都不显示,用于闪烁的实现
};

static unsigned char ucDisplayBuff[MAX_BIT];
/* ----------------------- Start implementation -----------------------------*/
void vLCM046Init(void)
{
 _delay_ms(200);
 //init the I/O port
 INIT_LCM( );
 vLCM046WriteCommand(LCM_COMMAND_INIT);
 vLCM046WriteCommand(LCM_COMMAND_RC);
 vLCM046WriteCommand(LCM_COMMAND_RC_ON);
 vLCM046WriteCommand(LCM_COMMAND_LCD_ON);
}
/*cs=p1.5 wr=p1.3  data="p1".2*/
void vLCM046WriteCommand( unsigned int usCommand )

 unsigned char i;
 
 //CS=0
 LCM_CS(1); _delay_us(100); 
 LCM_CS(0); _delay_us(100);
 
 //write 1
 LCM_CLK(0); _delay_us(100); 
 LCM_DATA(1);_delay_us(100);
 LCM_CLK(1); _delay_us(100); 
 
 //write 0
 LCM_CLK(0); _delay_us(100); 
 LCM_DATA(0);_delay_us(100);
 LCM_CLK(1); _delay_us(100); 

    //write 0
 LCM_CLK(0); _delay_us(100); 
 LCM_DATA(0);_delay_us(100);
 LCM_CLK(1); _delay_us(100); 
 
 for(i=9;i>0;i--)
 {
     LCM_CLK(0); _delay_us(100);
     if(usCommand&0x80) 
     {
      LCM_DATA(1);
     } 
     else   
     {
      LCM_DATA(0);
     }
     _delay_us(100);
     LCM_CLK(1); _delay_us(100); 
     usCommand<<=1; 
 }
 
 //CS=1
 LCM_CS(1);
 LCM_DATA(1);
}

void vLCM046WriteData( unsigned char ucAddr, unsigned char ucData )
{ unsigned char i;
 
 //init the I/O port
 INIT_LCM( );
 
 //CS=0
 LCM_CS(1); _delay_us(100); 
 LCM_CS(0); _delay_us(100);
 
 //write 1
 LCM_CLK(0); _delay_us(100); 
 LCM_DATA(1);_delay_us(100);
 LCM_CLK(1); _delay_us(100); 
 
 //write 0
 LCM_CLK(0); _delay_us(100); 
 LCM_DATA(0);_delay_us(100);
 LCM_CLK(1); _delay_us(100); 

    //write 1
 LCM_CLK(0); _delay_us(100); 
 LCM_DATA(1);_delay_us(100);
 LCM_CLK(1); _delay_us(100); 
 
 //write 0
 LCM_CLK(0); _delay_us(100); 
 LCM_DATA(0);_delay_us(100);
 LCM_CLK(1); _delay_us(100); 
 
 //write addr
 for(i=5;i>0;i--)
 {
     LCM_CLK(0); _delay_us(100);
     if(ucAddr&0x10) 
     {
      LCM_DATA(1);
     } 
     else   
     {
      LCM_DATA(0);
     }
     _delay_us(100);
     LCM_CLK(1); _delay_us(100); 
     ucAddr<<=1; 
 }
 
 //write data
 for(i=4;i>0;i--)
 {
     LCM_CLK(0); _delay_us(100);
     if(ucData&0x01) 
     {
      LCM_DATA(1);
     } 
     else   
     {
      LCM_DATA(0);
     }
     _delay_us(100);
     LCM_CLK(1); _delay_us(100); 
     ucData>>=1; 
 }
 
 //CS=1
 LCM_CS(1);
 LCM_DATA(1);
}

void vLCM046BitDisplay( unsigned char ucBit, unsigned char ucData )
{
 if(ucBit <= MAX_BIT)
 {
  ucDisplayBuff[ucBit] = 0;
  ucDisplayBuff[ucBit] = ucNumTrueValueTable[ucData];
  vLCM046WriteData( ( 2*ucBit - 2 ), ucDisplayBuff[ucBit]&0x0F );
  vLCM046WriteData( ( 2*ucBit -1 ), ucDisplayBuff[ucBit]>>4 );
 } 
}

系统分类: 单片机   |    用户分类:    |    来源: 原创

该用户于2008-12-23 21:09:16编辑过该文章

评论(0) | 阅读(73)
发表于:2008-12-16 9:15:49
标签:SMS  

0

一步一步写一个短信SMS协议栈FreeSmsStack(2)

如果你有兴趣,可以看看这个FreeSmsStack是怎么一步一步编写出来的。这个协议栈其实是参考了多个人的劳动成果,并不是从底层一点一点敲出来的,而是一开始就有一个整体的框架了。

这个框架在逻辑上从底层到高层分为:

ü         硬件驱动层(微控制器串口发送和接收)

ü         数值帧发送接收层(符合AT命令的数据帧的发送和接收)

ü         功能函数层(完成短消息的读、写和删除)

ü         协议层(短消息协议栈的开始、停止、删除等)

ü         用户应用层(用户根据项目的实际功能要求,增加自己的应用或处理函数)

这个文档是第二篇。第一篇可以在以前的博文中找到。具体的内容已经整理成如下的pdf文档。

pdf

系统分类: 嵌入式   |    用户分类:    |    来源: 原创

该用户于2008-12-16 16:35:35编辑过该文章

评论(0) | 阅读(156)
发表于:2008-11-4 16:03:37
标签:无标签

1

使用宏定义方便硬件相关的代码移植

    今天又犯了老错误。新板子用原来的老程序,需要修改一些管脚定义,由于开头的管脚的宏定义没有用好,导致函数中有个地方有句跟硬件相关的代码没有修改,调试了1天才发现问题。

    下面就详细介绍一下这个问题。想想问题在哪里,如何来避免这个问题。

     最初的程序是借鉴了别人的代码,有点盲目崇拜,直接拿来用,也没有去怀疑代码是否是最好的。具体的代码如下:

#define noACK 0
#define ACK 1

#define STATUS_REG_W  0x06
#define STATUS_REG_R  0x07
#define MEASURE_TEMP  0x03
#define MEASURE_HUMI  0x05
#define RESET         0x1e


#define setREAD       DDRB |=(1<<PB3); PORTB|=(1<<PB3);DDRB &= ~(1<<PB4)
#define setWRITE      DDRB |=(1<<PB3); DDRB |=(1<<PB4)//outb(DDRB, 0x03)
#define SCK(i)        if (i) PORTB|=(1<<PB3); else PORTB &= ~(1<<PB3)
#define DATA(i)       if (i) PORTB|=(1<<PB4); else PORTB &= ~(1<<PB4)

//  enum {TEMP, HUMI};


void delay_us(unsigned int us) {
  while (us) us--;
}


void delay_ms(unsigned int ms) {
  unsigned int outer1, outer2;
  outer1 = 2000;
  while (outer1) {
    outer2 = 10000;
    while (outer2) {
      while ( ms ) ms--;
      outer2--;
    }
    outer1--;
  }
}


void TransStart(void)
{
  DATA(1);//数据位置1 
  SCK(0);//sck清0
  delay_us(1);//延时
  SCK(1);//sck置1
  delay_us(1);//延时
  DATA(0);//数据变低
  delay_us(1);//延时
  SCK(0);//sck降低
  delay_us(5);//延时
  SCK(1);//sck置高
  delay_us(1);//延时
  DATA(1);//数据置高
  delay_us(1);//延时
  SCK(0);//sck清0
}


void ConnReset(void)
{
  unsigned int i;
  setWRITE;
  DATA(1); SCK(0);
  for(i=0; i<9; i++) {
    SCK(1);
    SCK(0);
  }
  TransStart();//发送开始信号
}


unsigned int GetDATA()
{
  return bit_is_set(PINB, PB4);
}


unsigned char WriteByte(unsigned char value) {
  unsigned char i, error="0";
  setWRITE;                  //设置为写
  for(i=0x80;i>0;i/=2)
  {
    if (i & value) DATA(1);//先输出最高位
    else DATA(0);
    SCK(1);                 //产生一个下降沿
    delay_us(5);
    SCK(0);
  }
  setREAD;                  //设置为读
  SCK(1);                   //SCK设置为高
  delay_us(1);              //延时
  error="GetDATA"();          //获取ACK数据
  SCK(0);                  
  return error;
}


unsigned char ReadByte(unsigned char ack) {
  unsigned char i,val=0;
  setREAD;                 //设置为读
  for(i=0x80;i>0;i/=2)
  {
    SCK(1);                //置高
    if (GetDATA()) val=(val | i);  //获取数据
    SCK(0);                        //拉低
  }
  setWRITE;                        //设置为写
  DATA(!ack);
  SCK(1);
  delay_us(5);
  SCK(0);
  return val;
}


unsigned char measure(unsigned int *p_value, unsigned char *p_checksum, unsigned char mode) {
  unsigned char lsb,msb,check;
  unsigned char error="0";
  unsigned int i;

  TransStart();//开始传输
  switch(mode) //发送温度或者湿度
  {
    case TEMP : error+=WriteByte(MEASURE_TEMP); break;
    case HUMI : error+=WriteByte(MEASURE_HUMI); break;
    default   : break;
  }
  setREAD;     //设置为读
  for(i=0;i<65535;i++) if (GetDATA()==0) break;//等待DATA电平变高
  if (GetDATA()) error+=1;  //如果变高,加1
  *p_value = ReadByte(ACK); //读字节
  *p_value<<=8;
  *p_value+= ReadByte(ACK);//再读一个字节
  *p_checksum = ReadByte(noACK);//读CRC
  return error;

    上面的代码跟硬件相关的地方有2个。一个是最初的宏定义部分。第二部分是上面红色的函数中,读取管脚状态的函数也跟硬件相关。我应用的时候,只注意到上面宏定义中跟硬件相关代码的修改,而没有注意到函数内部跟硬件相关的代码,结果半天没有调试通过。

    重新写了这部分代码,将与硬件相关的代码用宏定义的方式放在文件的开头。

 /* ----------------------- Defines ------------------------------------------*/
#define noACK 0
#define ACK 1

#define STATUS_REG_W  0x06
#define STATUS_REG_R  0x07
#define MEASURE_TEMP  0x03
#define MEASURE_HUMI  0x05
#define RESET         0x1e

//SCK--PB1 DATA--PB0
#define SCK_PORT      PORTB
#define SCK_PIN       PB1
#define SCK_DDR       DDRB

#define DATA_PORT     PORTB
#define DATA_PIN      PB0
#define DATA_DDR      DDRB

#define GET_DATA_PORT  PINB
#define GET_DATA_PIN   PB0

#define setREAD       SCK_DDR |= (1<<SCK_PIN); DATA_PORT|=(1<<DATA_PIN);DATA_DDR &= ~(1<<DATA_PIN)
#define setWRITE      SCK_DDR |= (1<<SCK_PIN);                         DATA_DDR |=(1<<DATA_PIN)
#define SCK(i)        if (i) SCK_PORT|=(1<<SCK_PIN); else SCK_PORT &= ~(1<<SCK_PIN)
#define DATA(i)       if (i) DATA_PORT|=(1<<DATA_PIN); else DATA_PORT &= ~(1<<DATA_PIN)

 

//  enum {TEMP, HUMI};

void delay_us(unsigned int us)
{
  while (us)
  {
     _delay_us(10);
     us--;
   }
}


void delay_ms(unsigned int ms)
{
  unsigned int outer1, outer2;
  outer1 = 2000;
  while (outer1) {
    outer2 = 10000;
    while (outer2) {
      while ( ms ) ms--;
      outer2--;
    }
    outer1--;
  }
}


void TransStart(void)
{
  DATA(1);//数据位置1 
  SCK(0);//sck清0
  delay_us(1);//延时
  SCK(1);//sck置1
  delay_us(1);//延时
  DATA(0);//数据变低
  delay_us(1);//延时
  SCK(0);//sck降低
  delay_us(5);//延时
  SCK(1);//sck置高
  delay_us(1);//延时
  DATA(1);//数据置高
  delay_us(1);//延时
  SCK(0);//sck清0
  delay_us(1);//延时
}


void ConnReset(void)
{
  unsigned int i;
  setWRITE;
  delay_us(1);//延时
  DATA(1); SCK(0);
  for(i=0; i<9; i++) {
    SCK(1);
 delay_us(1);//延时
    SCK(0);
 delay_us(1);//延时
  }
  delay_us(1);//延时
  TransStart();//发送开始信号
}


unsigned int GetDATA()
{
  return bit_is_set(GET_DATA_PORT, DATA_PIN);
}


unsigned char WriteByte(unsigned char value)
{
  unsigned char i, error="0";
  setWRITE; 
  delay_us(1);//延时                //设置为写
  for(i=0x80;i>0;i/=2)
  {
    if (i & value) DATA(1);//先输出最高位
    else DATA(0);
 delay_us(1);//延时
    SCK(1);                 //产生一个下降沿
    delay_us(5);
    SCK(0);
 delay_us(1);//延时
  }
  delay_us(1);//延时
  setREAD;                  //设置为读
  delay_us(1);//延时
  SCK(1);                   //SCK设置为高
  delay_us(1);              //延时
  error="GetDATA"();          //获取SCK数据
  SCK(0); 
  delay_us(1);//延时                
  return error;
}


unsigned char ReadByte(unsigned char ack)
{
  unsigned char i,val=0;
  setREAD;                 //设置为读
  delay_us(1);//延时
  for(i=0x80;i>0;i/=2)
  {
    SCK(1);                //置高
 delay_us(1);//延时
    if (GetDATA()) val=(val | i);  //获取数据
    SCK(0);                        //拉低
 delay_us(1);//延时
  }
  delay_us(1);//延时
  setWRITE;                        //设置为写
  delay_us(1);//延时
  DATA(!ack);
  delay_us(1);//延时
  SCK(1);
  delay_us(5);
  SCK(0);
  delay_us(1);//延时
  return val;
}


unsigned char measure(USHORT *p_value, unsigned char *p_checksum, unsigned char mode)
{
  //unsigned char lsb,msb;
  unsigned char error="0";
  unsigned int i;
  TransStart();//开始传输
  switch(mode) //发送温度或者湿度
  {
    case TEMP : error+=WriteByte(MEASURE_TEMP); break;
    case HUMI : error+=WriteByte(MEASURE_HUMI); break;
    default   : break;
  }
  setREAD;     //设置为读


  for(i=0;i<655;i++)
  {
   _delay_ms(1);
    if (GetDATA()==0)
    break;//等待DATA电平变高
  }
  if (GetDATA())
  {
      error+=1;  //如果变高,加1
   }

 *p_value = ReadByte(ACK); //读字节
  *p_value<<=8;
  *p_value+= ReadByte(ACK);//再读一个字节

  *p_checksum = ReadByte(noACK);//读CRC
  return error;

    这样,再做移植的话只需要将宏定义部分仔细修改一下即可,代码部分就不用操心了。参考别人的代码的时候,一定记着只是参考,要批判性地用。

 

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(0) | 阅读(125)
发表于:2008-11-3 17:28:19
标签:无标签

1

ATmega168 A/D 转换 使用连续转换和中断方式的例子

ATmega168的A/D转换可以实现单次转换和连续转换。下面的例子实现连续转换。

     说明:采用中断方式,4路AD单端输入,分别接入AD4~AD7。程序应用层认为AD通道是1~4,因此下面程序中选择通道做了特殊处理,ADMUX |= ( AI_CHANNEL1_PORT+ucChl-1 );  

     用户应用程序调用时,先调用vStartADConvert(),来完成一个通道的AD转换,然后调用fGetAIData(),得到具体的电压值。

     推荐的程序结构是:周期性地调用vStartADConvert(),将AD结果保存在本文件的数据结构xAIDatastruct_t xAIData[MAX_AI_CHANNEL]中;当用户需要数据时,再在需要的地方调用fGetAIData(),获取真实数值。

/* ----------------------- Defines ------------------------------------------*/
#define AREF 1.1

#define AI_CHANNEL1_PORT  4
#define AI_CHANNEL2_PORT  5
#define AI_CHANNEL3_PORT  6
#define AI_CHANNEL4_PORT  7

#define TRANSFER_TIMES    5   //多次转换求平均值时的转换次数

/* ----------------------- Static variables ---------------------------------*/
typedef struct
{
    volatile UBYTE  ucCurrentConvertTimes;
    volatile USHORT usValidData;
    volatile USHORT usTempData;
} xAIDatastruct_t;

STATIC xAIDatastruct_t xAIData[MAX_AI_CHANNEL];
STATIC volatile unsigned char ucADCurrentChannel;

/* ----------------------- Static functions ---------------------------------*/
void vADInit(void);


/* ----------------------- Start implementation -----------------------------*/


/******************************************
* 名称    :  vADInit
* 功能描述:  AD初始化,初始化4个AD输入通道,设置转换速率、内部参考电压源
* 输入参量:  无
* 输出参量:  无
* 调用子程: 
* 使用方法: 
--------------------------*/
void
vADInit(void)
{
  PRR &= ~_BV( PRADC );//
  ADMUX = _BV( REFS1) | _BV( REFS0 );

  ADCSRA = _BV( ADEN ) | _BV( ADPS2 )| _BV( ADPS1 )| _BV( ADATE ) ;
  ADCSRB="0x00";
}

void
vStartADConvert( UCHAR ucChl)

 vADInit();
 ADMUX |= ( AI_CHANNEL1_PORT+ucChl-1 );    //从第ucChl个通道开始进行转换,由于从外部AD通道从1开始,对应第4通道
 ADCSRA |= _BV( ADSC ) ;                   //开始AD转换,并且使能ad中断
 ADCSRA |= _BV( ADIE ) ;
 ucADCurrentChannel = ucChl-1;
}

ISR( ADC_vect, ISR_BLOCK )
{  
 ADCSRA &= ~_BV( ADIF );
 if(xAIData[ucADCurrentChannel].ucCurrentConvertTimes != 0)
     xAIData[ucADCurrentChannel].usTempData += ( int ) ADC;
 xAIData[ucADCurrentChannel].ucCurrentConvertTimes++;

 if( xAIData[ucADCurrentChannel].ucCurrentConvertTimes > TRANSFER_TIMES)
 {
  ADCSRA &= ~_BV( ADSC );                      //停止AD转换
  ADCSRA &= ~_BV( ADIE );                      //禁止中断

  xAIData[ucADCurrentChannel].usValidData = xAIData[ucADCurrentChannel].usTempData/TRANSFER_TIMES;
  xAIData[ucADCurrentChannel].usTempData = 0;
  xAIData[ucADCurrentChannel].ucCurrentConvertTimes = 0;
 }
}

float
fGetAIData( UCHAR ucChl)
{
 return ( xAIData[ucChl-1].usValidData*AREF/1024);
}

应用要点:切换通道后的第一次转换结果需要舍弃。上面的例子中,AD中断发生了6次,但是我们只利用其中的后5次。我测试发现,切换通道后的第一次AD转换的数值是上个通道的AD值。


 

系统分类: 嵌入式   |    用户分类:    |    来源: 原创

评论(0) | 阅读(191)
发表于:2008-10-13 15:03:15
标签:无标签

0

AVR管脚外部上拉电阻阻值选择问题

AVR微控制器的I/O口是双向口。具有如下的特点:

AVR IO具备多种IO模式:

   1 高阻态,多用于高阻模拟信号输入,例如ADC数模转换器输入,模拟比较器输入

   2 弱上拉状态(Rup=20K~50K),输入用。为低电平信号输入作了优化,省去外部上拉电阻,例如按键输入,低电平中断触发信号输入

   3 推挽强输出状态,驱动能力特强(>20mA),可直接推动LED,而且高低驱动能力对称.

在实际应用中,我使用了1M的外部上拉,用来测量霍尔器件的脉冲。结果发现没有动作的情况下也测量到了脉冲。于是做了如下的测量:

1,该管脚设置为输入,不使能内部上拉而是使用外部1M电阻上拉(PORTX为0),测量得到该管脚的电压大约是3.06(电源电压是3.37)

2,该管脚设置为输入,使能内部上拉(带着外部上拉的1M电阻),测量得到该管脚的电压大约是3.36(电源电压是3.37)

3,该管脚设置为输入,不使能内部上拉而是使用外部可调电阻上拉(PORTX为0),管脚电压随着外部上拉电阻的阻值的下降而升高,当外部可调电阻的组织大约是40K时,该管脚电压接近Vcc供电电压,并且降低电阻,电压也不再升高。

总结出一个规律,如果使用外部上拉电阻,该阻值应该不能超过40K,否则该引脚的电压将不能到达Vcc的电压。

更正:

上面的测量是有问题的,上面1中测量的电压为3.06,是由于万用表内阻的影响,换句话说,如果万用表的内阻是M级别的话,外部1M电阻和万用表相比已经足够大,因此本身会有比较大的压降,导致管脚上电压变低(该管脚的电压实际值应该是接近电源电压),具体可以参考下图。。原来的系统不工作应该是外部电阻太大引起的,具体的原因是什么哪?~点击开大图

系统分类: 嵌入式   |    用户分类:    |    来源: 原创

评论(0) | 阅读(170)
发表于:2008-8-18 17:02:57
标签:AVR  DW  

2

Mega168外部复位和单线调试共用时的管脚处理

目前很多单片机都具有调试、在线下载的功能。如AVR系列微控制器的DW接口,容许调试器(仿真器)通过VCCGNDRESET三个口与微控制器通信,完成调试和程序下载。而这些功能所用到的数据接口中一般包括RESET复位引脚。为了上电可靠,我们一般都设计了上电复位电路。上电复位电路最多的是使用阻容复位电路。

我在一次设计中用到了ATmega168,当复位引脚直接上拉一个电阻的时候,能够进入ISPDW模式。而当增加了阻容组成的上电复位后,单片机却进入不到调试模式了。点击看大图

 

上图是不能正常进入DW模式的电路图,RST管脚的电平变化受到了阻容复位电路的影响。

解决的办法是在微控制器的复位引脚和阻容复位电路之间增加一个电阻。如下图所示。

这样,当DW通过RST通信的时候,可以通过新增加的10K电阻来消弱复位电路对其的影响,从而能够实现正常的通信。

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(0) | 阅读(426)
发表于:2008-7-22 17:38:41
标签:无标签

1

编程规则

1,函数变量定义

数据的传递尽量通过函数的参数来实现,函数前面的函数返回值类型最好是表示函数执行的状态。

比如:我们通过串口接收一个字节数据,我们可以定义函数如下:

BOOL
xSmsPortSerialGetByte( CHAR * pucByte )
{
    *pucByte = UDR;
    return TRUE;
}

还可以定义如下:

Char xSmsPortSerialGetByte( void)

{
    return UDR;
}
第一种方法,调用函数后需要传递出一个接收到的数据,这个是通过函数的参数来传递的。第二种方法,是通过函数的返回值来传递的。

2,编译

代码编译后不能存在warning。

3, 文件名

软件项目的目录名和文件名都必须是英文字符。好多软件不认识汉字或者当有中文路径时会出错。比如,当AVR Studio4.14和WinAVR200(2008年9月能找到的两个软件的最新版本)配合使用时,如果项目文件存放目录存在中文时候,会出现不能找到makefile文件的错误。当目录都是中文的时候错误就消失了。

 

系统分类: 嵌入式   |    用户分类:    |    来源: 整理

评论(0) | 阅读(355)
发表于:2008-7-13 22:54:25
标签:编译警告  

1

以后一定注意不能忽略编译器的警告

1,为什么容易忽略编译器的警告信息?

    1)编程时处理各种error已经很让人恼火的了,error自然被放在次要位置;

    2)绝大多数下,程序在存在warnings的情况下,在短期内可以正常运行,我们根本看不到错误,导致warning近一步被轻视;

    3)没有养成好的工作习惯,带有warning的代码是不能交付的,而我们判断交付的标准中往往没有对代码提出更为细致的要求。

2,忽视编译警告往往会给我们造成重大损失

    最近的一个项目中,我的程序在实验室测试了1个星期没有出现问题。当设备部署到现场3天后,坏事情终于发生了:设备依次出现死机问题。

   再从头分析代码, 百思不得其解,痛不欲生的时候注意到了一个编译警告,说一个表达式一直为真。原来发生了下面的错误:

    unsigned char i;

    for( i = 0; i < 1000; i++)  {.....}

    变量类型的定义导致了表达式一直为真。为什么开始的测试中不会出现问题哪?原来,这段代码是必须程序运行一段时间后才会执行的一段代码,在短时间的测试中根本不会进入。

    看来编程真不能偷懒,偷懒必遭惩罚,你还要费比当时偷懒省的劲多好多倍的劲来弥补,并且这个弥补的过程中你还要承受巨大的压力。跟平时多流汗战时少流血的道理一样的。

    3)解决办法

    给自己的编程增加一个规则,带有编译警告的代码不能交付。

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(1) | 阅读(447)
发表于:2008-6-17 17:56:05
标签:无标签

1

引用没有声明的外部函数可能会导致严重问题

using a function without a valid prototype is VERY dangeours.

    在一个函数中调用另外一个文件中定义的函数,但是这个函数没有进行声明,会出什么问题哪?

    大多数的情况下可能会出现问题,有些情况下,可能是幸运不会出现问题。

     看下面这段代码:

    unsigned long ulWater_Max_Value=0xABCDEFUL;

    Puthexbyte(ulWater_Max_Value>>24);
    Puthexbyte(ulWater_Max_Value>>16);
    Puthexbyte(ulWater_Max_Value>>8);
    Puthexbyte(ulWater_Max_Value);

    其中Puthexbyte函数在另外一个c文件中进行了定义,但是在该文件对应的.h文件中,我没有对这个函数进行声明。

    这样,当运行上面的代码的时候,会导致错误的结果,输出的数据全部为0。

    改正的方法是,为每个外部函数在.h文件做一个相应的声明。每个需要调用这个函数的文件都要包含这个.h头文件。

    仍然是上面的代码,如果把变量定义为unsigned int 形式,却可以输出正确结果。这有点奇怪,绝对是侥幸,但是,为什么会对哪?即:

    unsigned int ulWater_Max_Value=0xABCD;

    //Puthexbyte(ulWater_Max_Value>>24);
    //Puthexbyte(ulWater_Max_Value>>16);
    Puthexbyte(ulWater_Max_Value>>8);
    Puthexbyte(ulWater_Max_Value);

    在不声明Puthexbyte函数的情况下,仍然能正确输出,为什么哪?

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(1) | 阅读(690)
发表于:2008-6-6 17:41:40
标签:无标签

1

一步一步写一个短信SMS协议栈FreeSmsStack(1)

一步一步写一个短消息收发协议栈(1

――基于TC35iATMega32的短消息协议栈FreeSmsStack

V1.0

bpesun@163.com

1.     目的

本项目的目的是完成一个建立在TC35i模块上的短消息协议栈。我给这个协议栈起的名字是FreeSmsStack。从名字上可以看出,这个协议栈是一个免费的开源协议栈。

短消息业务(SMS)作为GSM的一种增值服务,随着GSM网络覆盖范围的不断扩大,得到了迅速发展,它具有传输速度快,费用低,不占用语音通信通道等优点,因而在远程智能控制系统中得到了广泛的应用,如:基于GSMGPS的车辆跟踪监视系统,基于GSM的远程LED信息发布系统等。

2.     FreeSmsStack协议栈的功能

目前,这个协议栈能完成如下的功能:

ü         中、英文短信发送

ü         中、英文短信接收

ü         短信删除

ü         振铃后挂断来电并且反馈短信到来电号码

ü         普通AT命令发送

注意:目前,中文短信编码不能通过单片机实现,只能通过查表的方式将某些短信编码存储在单片机中。

3.     FreeSmsStack协议栈对硬件的需求

    下面列出的是本协议栈在所有功能使能的情况下对单片机的需求,可以看出普通的中档次的单片机都能满足要求。

ü         具有一个串口,具备发送寄存器空中断和接收到中断

ü         具有一个定时器

ü         RAM最好有1.5K以上(实现全部功能)

3.1. 项目硬件

项目的硬件结构如下图所示。主要由GSM模块TC35i、单片机ATmega32、电源等模块组成。单片机和TC35i模块之间通过TTL串口进行通信。

 

下面简单介绍一下项目中所用到的硬件。

3.2. TC35i

短消息模块采用西门子的TC35i该模块的特性如下。

信息传送内容

语音和数据

电源

单电源 3.3V 4.8V

频段

双频GSM900MHz DCS1800 MHz(Phase 2+)

发射功率

2W GSM900MHz Class 4 1W DCS1800MHz Class 1

SIM 卡连接方式

外接

天线

由天线连接器连接外部天线

温度范围

工作温度:-20°C to +55°C 储存温度:-30°C to +85°C

工作电流损耗

通话模式: 300mA (