这是曾经本科生时期的制作,一个用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;
}
这个功能还是很简单的。
这是曾经本科生时期的制作,一个用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;
}
这个功能还是很简单的。
举报