基於ATmega8的測速計設計
這是曾經本科生時期的製作,一個用atmega8a晶片做的測速計。當時選用atmega8a的原因很簡單,學生時代做東西,都是撿到啥晶片就用啥,只要效能還能過得去就可以了。這款微控制器效能一般,但是比at89c51強多了(最主要是剩下的多),就是燒寫程式時候需要配置熔絲位,一時間不太習慣。整個工程是用iar for avr寫的,因為那時候一直用msp430,習慣了iar的介面。
首先是選標頭檔案,iom8.h定義了相關的暫存器,裝好iar就能用了。
//這裡是iar裡面的
#include <iom8.h>
#include<intrinsics.h>
//後面是自己的
#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<intrinsics.h>
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<<PD2)|(1<<PD3);
GICR |= 0xC0;//使能int_0 int_1中斷
}
*/
void int_init(void)
{
MCUCR |= 0x02;//int0 下降沿中斷
MCUCSR|= 0x00;
PORTD|=(1<<PD2);
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;
}
這個功能還是很簡單的。
相關文章
- 基於原型的角色設計方法原型
- 基於 esbuild 的 universal bundler 設計UI
- 基於shiro RBAC的表設計
- 基於UDP程式設計UDP程式設計
- vivo 基於 JaCoCo 的測試覆蓋率設計與實踐
- 基於FPGA的DDS研究與設計FPGA
- 基於MATLAB的水果分級設計Matlab
- 基於MaxCompute的拉鍊表設計
- 基於Atmega8微控制器的串列埠收發程式串列埠
- 通用查詢設計思想(2)- 基於ADO.Net的設計
- 基於介面的測試工具研發:使用GUI設計簡易計算器GUI
- 非同步程式設計:基於事件的非同步程式設計模式(EAP)非同步程式設計事件設計模式
- 聊聊基於敏捷的度量指標設計敏捷指標
- 基於原型的遊戲角色設計方法原型遊戲
- 基於promise的阻塞式佇列設計Promise佇列
- iOS中基於協議的路由設計iOS協議路由
- 基於SpringCloud的微服務架構設計SpringGCCloud微服務架構
- 基於RBAC的許可權設計模型模型
- 如何設計一個流計算基準測試?
- 基於頭肩部檢測的過線客流統計
- 基於人形檢測的劃區域客流統計
- 基於位運算的許可權設計
- 基於Verilog的陣列乘法器設計陣列
- 基於 Angular Material 的 Data Grid 設計實現Angular
- 基於Java反射的定時任務設計Java反射
- 基於php的公司企業網站設計PHP網站
- 基於 Laravel 和 Redis 的點贊功能設計LaravelRedis
- 基於Redis的任務排程設計方案Redis
- 基於ARM的電子密碼鎖的設計密碼
- 基於函數語言程式設計的領域驅動設計 - Scott Wlaschin函數程式設計
- 系統設計:如何設計一個類似於Tinder的基於位置的社交搜尋應用
- 基於Python的滲透測試資訊收集系統的設計和實現Python
- 基於AI的移動端自動化測試框架的設計與實踐AI框架
- 基於相關畢業設計論文下載基於WEB,基於java基於JSPWebJavaJS
- 380【畢設課設】基於STM32防久坐_睡眠監測控制系統設計
- 基於JaCoCo的Android測試覆蓋率統計(二)Android
- Java畢業設計_基於MySQL網盤管理系統的設計與實現JavaMySql
- 非同步程式設計:.NET 4.5 基於任務的非同步程式設計模型(TAP)非同步程式設計模型