单片机交流
直播中

李星童

7年用户 974经验值
私信 关注
[问答]

怎么实现基于ATmega8的测速计设计?

怎么实现基于ATmega8的测速计设计?

回帖(1)

贺若龙

2021-9-24 14:41:34
这是曾经本科生时期的制作,一个用atmega8a芯片做的测速计。当时选用atmega8a的原因很简单,学生时代做东西,都是捡到啥芯片就用啥,只要性能还能过得去就可以了。这款单片机性能一般,但是比at89c51强多了(最主要是剩下的多),就是烧写程序时候需要配置熔丝位,一时间不太习惯。整个工程是用iar for avr写的,因为那时候一直用msp430,习惯了iar的界面。
首先是选头文件,iom8.h定义了相关的寄存器,装好iar就能用了。


//这里是iar里面的
#include
#include
//后面是自己的
#include"bianliangshengming.h"
#include"hanshushengming.h"
#include"hanshudingyi.h"
#include"lcd.h"
#include"int.h"
主函数就这么写了,主要是一堆初始化,最后一个while(1),主要程序都是在中断里面,因为检测只有在外界触发了传感器才需要进行。


void main(void)
{
        init_devices();
        timer1_init();
        lcd();
        timer0_init();
        while(count2<10000)
        {
                if(anjian==0)
                {
                        DelayNms(3);
                        if(anjian==0);
                        {
                                key=1;
                                while(anjian==0);
                                break;
                        }
                }
        }
        count2=0;
        TCCR0=0x00;
        lcd1();
        timer0_init();
        while(count2<30000)
        {
        }
        TCCR0=0x00;
       
        TCCR1B=0X00;
        led0=0;
        led1=0;
        count2=0;
        timer2_init();
        if(!key)//选择模式,当时有两个检测模式,算法不太一样,具体不记得了
        {     
                LcdWriteCom(0x01);
                LCD_write_string(0,1,"MODE1 Running.....");
        }
        else
        {   
                LcdWriteCom(0x01);
                LCD_write_string(0,1,"MODE2 Running.....");
        }
        timer0_init();
        while(count2<5000)
        {
        }
        TCCR0=0x00;
        int_init();
        // DelayNms(5000);
        timer1_init();
        while(1)
        {
                __no_operation();
        }
}
一系列的外设初始化写在另一个文件,用了1602作为显示,这些初始化代码专门写一个文件。


#ifndef __LCD_H_
#define __LCD_H_
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
#define LCD1602_4PINS 1


/**********************************
包含头文件
**********************************/


//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif


#ifndef uint
#define uint unsigned int
#endif


/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS PORTC
#define LCD1602_E   PORTC_Bit4
#define LCD1602_RW PORTD_Bit5
#define LCD1602_RS PORTB_Bit0


                                  


#endif
/*void Lcd1602_Delay1ms(unsigned int ms)
{
  unsigned int i;
  for(;ms>0;ms--)
    for(i=0;i<2*4*143;i++);
}*/




/*******************************************************************************
* 函 数 名         : LcdWriteCom
* 函数功能                   : 向LCD写入一个字节的命令
* 输    入         : com
* 输    出         : 无
*******************************************************************************/
#ifndef         LCD1602_4PINS         //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com)          //写入命令
{
        LCD1602_E = 0;     //使能
        LCD1602_RS = 0;           //选择发送命令
        //LCD1602_RW = 0;           //选择写入
       
        LCD1602_DATAPINS = com;     //放入命令
        DelayNms(1);                //等待数据稳定


        LCD1602_E = 1;                  //写入时序
        DelayNms(5);          //保持时间
        LCD1602_E = 0;
}
#else
void LcdWriteCom(uchar com)          //写入命令
{
        LCD1602_E = 0;         //使能清零
        LCD1602_RS = 0;         //选择写入命令
        //LCD1602_RW = 0;         //选择写入


        LCD1602_DATAPINS = com>>4;        //由于4位的接线是接到P0口的低四位,所以传送高四位用改
        DelayNms(1);


        LCD1602_E = 1;         //写入时序
        DelayNms(5);
        LCD1602_E = 0;


//        Lcd1602_Delay1ms(1);
        LCD1602_DATAPINS = com ; //发送低四位
        DelayNms(1);


        LCD1602_E = 1;         //写入时序
        DelayNms(5);
        LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名         : LcdWriteData
* 函数功能                   : 向LCD写入一个字节的数据
* 输    入         : dat
* 输    出         : 无
*******************************************************************************/                  
#ifndef         LCD1602_4PINS                  
void LcdWriteData(uchar dat)                        //写入数据
{
        LCD1602_E = 0;        //使能清零
        LCD1602_RS = 1;        //选择输入数据
        LCD1602_RW = 0;        //选择写入


        LCD1602_DATAPINS = dat; //写入数据
        DelayNms(1);


        LCD1602_E = 1;   //写入时序
        DelayNms(5);   //保持时间
        LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat)                        //写入数据
{
        LCD1602_E = 0;          //使能清零
        LCD1602_RS = 1;          //选择写入数据
        //LCD1602_RW = 0;          //选择写入


        LCD1602_DATAPINS = dat>>4;        //由于4位的接线是接到P0口的低四位,所以传送高四位用改
        DelayNms(1);


        LCD1602_E = 1;          //写入时序
        DelayNms(5);
        LCD1602_E = 0;


        LCD1602_DATAPINS = dat ; //写入低四位
        DelayNms(1);


        LCD1602_E = 1;          //写入时序
        DelayNms(5);
        LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名       : LcdInit()
* 函数功能                 : 初始化LCD屏
* 输    入       : 无
* 输    出       : 无
*******************************************************************************/                  
#ifndef                LCD1602_4PINS
void LcdInit()                                                  //LCD初始化子程序
{
        LcdWriteCom(0x38);  //开显示
        LcdWriteCom(0x0c);  //开显示不显示光标
        LcdWriteCom(0x06);  //写一个指针加1
        LcdWriteCom(0x01);  //清屏
        LcdWriteCom(0x80);  //设置数据指针起点
}
#else
void LcdInit()                                                  //LCD初始化子程序
{
        LcdWriteCom(0x32);         //将8位总线转为4位总线
        LcdWriteCom(0x28);         //在四位线下的初始化
        LcdWriteCom(0x0c);  //开显示不显示光标
        LcdWriteCom(0x06);  //写一个指针加1
        LcdWriteCom(0x01);  //清屏
        LcdWriteCom(0x80);  //设置数据指针起点
}
#endif






void LCD_set_xy( unsigned char x, unsigned char y ) //写地址函数
{
    unsigned char address;
    if (y == 0) address = 0x80 + x; // 最高位是1,另七位才是地址 故有+0x80
    else if(y==1)  address = 0xc0 + x;
   else if(y==2)  address=0x80+x+0x14;
    else address=0xc0+x+0x14;
    LcdWriteCom( address);
}


void LCD_write_string(unsigned char X,unsigned char Y,unsigned char *s) //列x=0~15,行y=0,1
{
    LCD_set_xy( X, Y ); //写地址   
    while (*s) // 写显示字符
    {
      LcdWriteData( *s );
      s ++;
    }
      
}








void LCD_write_mode(unsigned char X,unsigned char Y,unsigned long int count)
{
  uchar D[7];
  count/=100;
  D[6]=0;
  D[5]='s';
  D[4]=count%10+48;              
  D[2]=(count%100)/10+48;        
  D[1]=(count%1000)/100+48;      
  D[0]=(count%10000)/1000+48;
  D[3]='.';
  LCD_write_string(X,Y,D);
}
相关的定时器等配置如下


#include
void lcd(void)
{
  DelayNms(50);
  LCD_write_string(0,0,"10s choose mode");
}
void lcd1(void)
{
  DelayNms(50);
  LCD_write_string(0,0,"Speedtest will start");
// DelayNms(20);
  LCD_write_string(0,1," after 30 seconds ");
  //DelayNms(2000);
}


/**************延时Nms*************************/       
void DelayNms(unsigned int ms)
{
  unsigned int i;
  for(;ms>0;ms--)
    for(i=0;i<4*143;i++);
}


//定时器T0初始化,计时0.5ms
void timer0_init(void)
{
TCCR0  = 0x00;//停止定时器
TCNT0  = 0x83;//初始值
TIMSK |= 0x01;//中断允许
TCCR0  = 0x03;//启动定时器
}


//外中断初始化
/*void int_init(void)
{
MCUCR |= 0x0A;//int0 int1 下降沿中断
MCUCSR|= 0x00;
PORTD|=(1< GICR  |= 0xC0;//使能int_0 int_1中断
}
*/
void int_init(void)
{
MCUCR |= 0x02;//int0 下降沿中断
MCUCSR|= 0x00;
PORTD|=(1< GICR  |= 0x40;//使能int_0 中断
}
void init_devices(void)
{
__disable_interrupt(); //禁止所有中断
MCUCR  = 0x00;
MCUCSR = 0x80;//禁止JTAG
GICR   = 0x00;
Portinit();
LcdInit();
__enable_interrupt();
}//开全局中断




void Portinit(void)
{
  DDRC=0XFF;
  DDRB=0XFF;
  PORTC=0XFF;
  DDRD=0Xff;
  PORTD=0XFF;
  
}
void timer1_init(void)
{
        DDRB=0XFF;
        TCCR1A=0XF2;
        TCCR1B=0X19;
        OCR1A= 0x32;//匹配A值
        OCR1B = 0x32;//匹配B值
        ICR1 = 0x64;//输入捕捉匹配值
}


void timer2_init(void)
{
        TCCR2  = 0x00;//停止定时器
        ASSR   = 0x00;//异步时钟模式
        TCNT2  = 0x83;//初始值
        TIMSK |= 0x40;//中断允许
        TCCR2  = 0x03;//启动定时器
        
}












void end(void)
{
    TCCR0  = 0x00;
    LcdWriteCom(0x01);
    GICR_Bit6=0;
}
中断程序用来计时


#pragma vector=INT0_vect
__interrupt void INT0_Server(void)//  传感器停止计时
{
  if(key){
  if(!s)
  {  
    TCNT0 = 0x83;   
    count2=count1;
    s=1;
  }
  else
  {
   end();
   unsigned long int count3;
   count3=count1+5*count1-5*count2;
   LCD_write_string(0,0,"T1:");
   LCD_write_mode(5,0,count2);
   LCD_write_string(0,1,"T2:");
   LCD_write_mode(5,1,count1);
   LCD_write_string(0,2,"Time:");
   LCD_write_mode(0,3,count3);
  }
  }
  else
  {
    end();
    LCD_write_string(0,0,"Time:");
    LCD_write_mode(0,1,count1);
  }
}




#pragma vector=TIMER0_OVF_vect
__interrupt void TIMER0_OVF_Server(void)
{
  TCNT0 = 0x83;
  count2+=2;
}


#pragma vector=TIMER2_OVF_vect
__interrupt void TIMER2_OVF_Server(void)
{
  TCNT2 = 0x83;
  count1+=1;
}
这个功能还是很简单的。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分