首先,祝福各位同仁,光棍節快樂!
今天,給我最好的節日禮物就是,我自己研發的AVR微控制器芯片開發板,1602液晶屏實驗成功!我很欣慰.寫了一整天的程序,反復實驗,最終在凌晨0點.終于成功了.
在此過程中,最大的問題莫過于那個所謂配套的1602液晶屏數據手冊!這個手冊簡直是誤人子弟,里面資料寫的很含糊.并且有錯誤,而導致我反復試驗失敗,最終,我使用了通用的1602液晶屏數據手冊,才得以成功.
我自制的AVR開發板尺寸和我買的51開發板差不多大小,ATmega16最小系統,8位數碼管,藍光流水燈,isp編程接口.過載保護保險絲,兩個74hc573鎖存器.1602液晶屏都已焊接完成,萬用板是12X18cm的單孔玻纖板(質量不太好,便宜沒好貨).現在我才發現不夠用,模塊數量相同的兩塊實驗板,手工焊接的一定要比機器印刷的大2~3倍才行.....
沒辦法,我只能用5X7cm的萬用板做小模塊,ADC模塊,DS1302時鐘模塊,激光二極管模塊等等,然后用杜邦線把它們和AVR核心板鏈接起來,目前計劃是這樣的,往往計劃很豐滿,實際很骨感,傷腦筋啊,,,
此次,首次接觸了12864大液晶,能顯示中文,和超聲波測距傳感器,這得好好研究一下,我一直想要了解一下2.4g無線傳輸模塊,和陀螺儀傳感器,還有GPS模塊,不過那些還早,把AVRATMEGA16學的差不多了,再了解,也不遲.
/*
Program name: AVR ATMEGA16 1602驅動程序
初次實驗通過時間: 2013-11-11 00:04:01 ^_^ ;
注意:在bysy()函數中嚴重出錯!下次注意!
while((PINA&0x80)==0x80); 此語句檢測到PA7為零時終止循環;表明空
閑狀態
心得:
AVR單片機的IO口位操作比較復雜,
由三個寄存器控制IO口的輸出與輸入;
DDRn(輸出/輸入控制) 寄存器;
PORTn(輸出時控制數據,輸入時控制內部上拉電阻)寄存器;
PINn(用于讀取IO口數據)寄存器;
最終校驗通過時間: 2013年11月12日15:12:28
*/
#include <iom16v.h>
#include <macros.h>
#define uint8 unsigned char
#define uint16 unsigned int
//========IO口位操作========================================
void rs(uint8 h) //數據/指令選擇操作;
{
if(h)
PORTB|=1<<3; //置一;
else
PORTB&=~(1<<3); //清零;
}
void rw(uint8 h) //讀/寫選擇操作;
{
if(h==0)
{
PORTB&=~(1<<4); //清零;
}
else
{
DDRA=0X00;
PORTA=0XFF;
PORTB|=1<<4; //置一;
}
}
void e(uint8 h) //傳輸使能位;
{
if(h)
{
PORTB|=1<<5; //置一;
}
else
PORTB&=~(1<<5);//清零;
}
//========================================================
void ddra(uint8 h) //PA口輸入輸出函數;
{
if(h)
{
DDRA=0XFF; //輸出模式;
PORTA=0xff;
}
else
{DDRA=0X00; PORTA=0XFF; } //輸入模式并且有上拉;
}
void busy() //繁忙檢測;
{
ddra(0); //設置PA口為輸入,有上拉;
do
{
e(0); //傳輸使能為0;
rs(0); //指令;
rw(1); //讀;
e(1); //e為高電平;
}while((PINA&0x80)==0x80);//如果讀到數據是01111111,表示空閑狀態,跳出循環;
e(0);
ddra(1); //PA口輸出狀態;
}
void delay() //小延時;
{
uint8 j=0;
j=1;
}
void w_cmd(uint8 cmd)
{
busy(); //繁忙檢測通過時,PA口為輸出狀態,默認輸出0xff;
PORTA=cmd; //向PA口裝載數據;
rs(0); //指令;
rw(0); //寫入;
e(1); //傳輸使能脈沖高;
delay(); //延時;
e(0); //傳輸使能脈沖低;
}
void w_dat(uint8 dat)
{
busy(); //繁忙檢測通過時,PA口為輸出狀態,默認輸出0xff;
PORTA=dat; //向PA口裝載數據;
rs(1); //數據;
rw(0); //寫入;
e(1); //傳輸使能脈沖高;
delay(); //延時;
e(0); //傳輸使能脈沖低;
}
void init_1602()
{
w_cmd(0x3c); //寫入顯示設置:8位數據,兩行,5x10顯示;
w_cmd(0x0c); //整屏顯示,光標不閃,字符不閃;
w_cmd(0x06); //寫入一個數據時地址自動加一.整屏不移動;
w_cmd(0x01); //寫入'清屏'指令;
}
void display(uint8 addr ,uint8 dat )//可在任意位置顯示字符,
{ //addr地址,dat數據;
w_cmd(addr);
w_dat(dat);
}
void main(void) //====主函數=================
{
uint8 i=0, j=0x80,ak[]="I'am iron man!"; //要顯示的字符串"我是鋼鐵俠!"
uint8 sj[]="2013-11-11 ^_^"; //今天的日期;
uint16 s=0; //16位的變量;
DDRB=0XFF; //PB口輸出狀態;
PORTB=0X03; //PB0=1;PB1=1;
DDRA=0XFF; //PA口輸出狀態;
PORTA=0X00; //8個數碼管共陰極為'0'.八位陽極為'0';
PORTB=0X00; //鎖存數據;
init_1602(); //液晶屏初始化;
w_cmd(0x81); //初始化完成以后先發送要寫入的數據的顯示位置.
//0x81是第一行,第1位. 0x80是第0位;
while(ak[i]!='\0') //將ak[]數組內的所有數據發送;
{
w_dat(ak[i++]); //每發送一個字節數據,數據的存儲地址自動加一;
for(s=0;s<50000;s++); //延時一下,字符會有一個,一個顯示的效果;
}
w_cmd(0xc1); //發送第二排的數據地址,接下來字符會在第二排第1位開始顯示;
i=0;
while(sj[i]!='\0') //將sj[]數組內的數據全部發完;
{
w_dat(sj[i++]);
for(s=0;s<25000;s++); //效果延時;
}
while(1); //死亡循環;
}