本文主要是關于發(fā)光二極管的相關介紹,并著重對使用繼電器的發(fā)光二極管閃爍電路進行了詳盡的描述。
如何用繼電器的發(fā)光二極管閃爍電路圖
原理圖如圖一
連接電路前先不要接二極管D1,一會再解釋二極管的作用。三極管是2n3904 NPN型三極管,基極電阻68歐姆,要把圖中的5v電源vcc1和gnd1分別接到單片機的電源和地上.,
實物圖如下,圖二和圖三分別是LED燈亮和滅的照片。雖然我拿個一個開發(fā)板,但是只用了其單片機的最小系統(tǒng)。
用示波器測三極管集電極的波形,發(fā)現(xiàn)有圖五所示的一個尖刺,分析過后,是因為繼電器本身就是一個線圈,在電流突然變化的瞬間會起到阻礙其變化的作用,左移在繼電器的兩端并聯(lián)一個二極管,穩(wěn)定輸出的作用。加入二極管后的波形如圖六中最后一組波形。
控制單片機P2^0口的代碼如下:
#include《reg52.h》
#include《intrins.h》
sbit P20=P2^0 ;
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
P20=1;
Delay1000ms();
P20=0;
Delay1000ms();
}
}
LED閃爍電路
該Linux驅動用來控制開發(fā)板上的4個LED燈,即通過向Linux驅動發(fā)送數(shù)據(jù)可以控制LED燈的開關。LED驅動提供兩種交互方式:命令和讀寫設備文件。
測試LED驅動之前需用USB線連接開發(fā)板,然后打開開發(fā)板。成功啟動后,執(zhí)行build.sh腳本文件編譯和安裝LED驅動。build.sh腳本文件會自動將s3c6410_leds.ko文件上傳到開發(fā)板并安裝。LED驅動只能在開發(fā)板上安裝,build.sh執(zhí)行了build_s3c6410.sh腳本文件進行編譯和安裝。LED驅動會建立一個/dev/s3c6410_leds設備文件,該Linux驅動可控制4個LED,通過向設備文件發(fā)送長度為1到4的字符串可以控制這4個LED的開關。1表示開,0表示關。字符串長度不足4個,相當于后面補0。執(zhí)行命令
“# adb shell “echo ‘1’》 /dev/s3c6410_leds” #打開第一個LED,其他的都關閉
# adb shell “echo ‘1010’》 /dev/s3c6410_leds” #第一個和第三個LED打開,第二個和第四個關閉
# adb shell “echo ‘1111’》 /dev/s3c6410_leds” #打開所有的LED”可控制開發(fā)板上的LED。可使用命令“# sh ~/drivers/s3c6410_leds/test_leds.sh”執(zhí)行test_leds.sh腳本文件測試LED。執(zhí)行腳本文件后,開發(fā)板上的4個LED會根據(jù)0到15的二進制形式控制LED,第一個為最低位。腳本文件使用的是標準的Bash Shell,如果在Ubuntu下無法成功執(zhí)行,是因為其將dash作為默認的腳本解析器。可使用命令“# dpkg-reconfigure dash”將默認腳本解析器改成Bash,出現(xiàn)設置界面時,選擇“否”,再回車即可。
創(chuàng)建LED驅動的設備文件,步驟如下;1.描述設備文件需要使用一個cdev結構體,該結構體在《Linux內核源代碼》/include/linux/cdev.h文件中定義。其中的大多數(shù)成員變量只需調用cdev_init()就可被初始化,該函數(shù)在《Linux內核源代碼》/fs/char_dev.c文件中。若要在一個Linux驅動中建立多個設備文件,cdev.count變量的值就是要建立的設備文件數(shù)。這些設備文件對應的cdev結構體就通過cdev.list.prev和cdev.list.next指針變量連接,從而形成一個雙向鏈表。cdev.owner變量未在cdev.init函數(shù)中初始化,使用語句“l(fā)eds_cdev.owner=THIS_MODULE;”來初始化2.Linux設備文件的設備號分為主設備號和次設備號。用一個int類型表示,其中前12位表示主設備號,后20位表示次設備號。設備號有兩種指定方法:直接在代碼中指定和動態(tài)分配。第一種方法雖比較直觀,但如果主設備號和次設備號已存在,建立設備文件就會失敗。以防萬一,可使用alloc_chrdev_region()自動分配一個未使用的主設備號。習慣上將次設備號設為0。函數(shù)原型為int alloc_chrdev_region(dev_t*dev,unsigned baseminor,unsigned count,const char *name),其中dev表示設備號指針,函數(shù)會隨機分配一個未使用的主設備號,根據(jù)baseminor參數(shù)值分配次設備號。count表示分配的次設備號范圍。name表示設備文件名稱。多個Linux設備文件可擁有同一個主設備號,但兩個設備的主設備號和次設備號不能都一樣。在使用函數(shù)自動分配設備號時,baseminor和count參數(shù)不要設太大,否則次設備號會溢出,且主設備號會進位,從而變成下一個主設備號。若要直接指定設備號,需使用register_chrdev_region()注冊字符設備區(qū)域,該函數(shù)在《Linux內核源代碼》/fs/char_dev.c文件中實現(xiàn),原型為:int register_chrdev_region(dev_t from,unsigned count,const char *name),from表示設備號,count表示次設備號范圍,name表示設備文件名稱。一般采用分別指定主設備號和次設備號的方式指定設備號,需要MKDEV宏將主設備號和次設備號組合成設備號-“int dev_number=MKDEV(major,minor);”。也可分別使用MAJOR和MINOR宏從設備號中獲取主設備號和次設備號,代碼為:“int major=MAJOR(dev_number); int minor=MAJOR(dev_number);”3.cdev_add()用于將字符設備添加到probes數(shù)組中。函數(shù)在《Linux內核源代碼》/fs/char_dev.c文件中實現(xiàn),原型為
“int cdev_add(struct cdev *p,dev_t dev,unsigned count){
p-》dev=dev;
p-》count=count;
return kobj_map(cdev_map,dev,count,NULL,exact_match,exact_lock,p);
}”,調用該函數(shù)需指定設備文件指針p、設備號dev和設備文件數(shù)量count。在該函數(shù)還調用了一個重要的函數(shù)kobj_map,此函數(shù)負責將設備文件的相關信息添加到保存已建立的設備文件的probes數(shù)組中。kobj_map()和probes數(shù)組都在《Linux內核源代碼》/drivers/base/map.c文件中4.struct class包含一些與設備文件有關的變量及一些回調函數(shù)指針變量,使用class_create宏創(chuàng)建struct class,代碼為
“struct class *leds_class=NULL;
leds_class=class_create(THIS_MODULE,“dev_name”);”,dev_name是設備文件名稱。class_create宏實際上使用了_class_create()創(chuàng)建struct class。該函數(shù)在《Linux內核源代碼》/drivers/base/class.c文件中實現(xiàn)5.device_create()用于創(chuàng)建設備文件,該函數(shù)在《Linux內核源代碼》/include/linux/device.h文件中定義,在《Linux內核源代碼》/drivers/base/core.c文件中實現(xiàn)。可使用代碼“device_create(leds_class,NULL,dev_number,NULL,DEVICE_NAME);”調用device_create()創(chuàng)建設備文件,其中l(wèi)eds_class表示struct class,dev_number表示設備號,DEVICE_NAME表示設備文件的名稱。編寫leds_create_device()時應了解:①DEVICE_COUNT表示建立設備文件的個數(shù)②alloc_chrdev_region()的第二個參數(shù)表示分配的起始次設備號。如果第三個參數(shù)的值大于1,函數(shù)會依次分配次設備號③采用自動分配設備號的方式創(chuàng)建設備文件,建議使用MAJOR和MINOR宏獲取主設備號和次設備號,并分別保存在major和minor變量中,以備之后使用到④LED驅動的設備號保存在dev_number變量中,要將leds_cdev.dev變量的值賦給dev_number變量。leds_init()是LED驅動的初始化函數(shù),在函數(shù)中直接調用leds_create_device()即可。若將S3C6410_LEDS_MAJOR設為0,系統(tǒng)會自動分配一個未使用的主設備號,次設備號仍是10.在每次裝載LED驅動時主設備號可能會不一樣,但次設備號總是10。
卸載LED驅動的設備文件:卸載操作會稍簡單一些,需依次調用device_destroy、class_destroy和unregister_chrdev_region()。leds_destroy_device()用于卸載LED驅動的設備文件,leds_exit()是LED驅動的卸載函數(shù),它通過調用leds_destroy_device()來完成卸載LED驅動設備文件的工作。
設置寄存器與初始化LED驅動:ARM處理器有多個寄存器,通過設置不同寄存器的值。可以設置LED引腳的狀態(tài)、打開或禁止上拉電路以及控制LED的亮和滅。我們必須知道的有:①LED有兩個引腳:GPB0和GPB1,其中一個引腳連接到了ARM處理器的GPI0端口,另一個引腳經過一個限流電阻連接到電源VCC3上。當GPI0端口為低電平時,LED兩端產生電壓差,LED有電流通過發(fā)光;反之當GPI0端口為高電平時,LED中沒有電流通過,燈熄滅。高低電平之間切換非常快,LED亮滅之間有一定的延遲②控制LED需要通過3個寄存器完成,GPMCON端口配置寄存器、GPMDAT端口數(shù)據(jù)寄存器和GPMPUD端口上拉電路寄存器③每一個寄存器可以使用4個字節(jié),即一個int類型數(shù)據(jù)占用的空間④使用GPMCON寄存器的低16位將LED的兩個端口GPB0、GPB1的屬性設為Output。每4位設置一個LED,共4個LED。output的值是0001,若使用十六進制表示,寄存器的低16位的值是0x1111⑤使用GPMDAT寄存器的低4位控制4個LED的亮、滅。每一位控制一個LED,最低位控制離電池最近的LED。0表示亮、1表示滅⑥使用GPMPUD寄存器的低8位分別打開4個LED的上拉電路。每兩位控制一個LED的上拉電路。10為打開上拉電路。使用十六進制的話,GPMPUD寄存器的低8位是0xAA,才能同時打開4個LED的上拉電路。以上3個寄存器在內存中都有一個虛擬地址。向這些地址寫入數(shù)據(jù)后,ARM處理器會使用一套算法將虛擬地址映射成物理地址,并根據(jù)物理地址將數(shù)據(jù)寫入相應的硬件端口。ARM處理器中的GPMCOM、GPMDAT和GPMPUD的虛擬地址在Linux內核中都使用了宏定義。為了跟蹤這些宏,需再加兩個include路徑:/root/kernel/linux_kernel_2.6.36/arch/arm/mach-s3c64xx/include和/root/kernel/linux_kernel_2.6.36/arch/arm/plat-samsung/include。這三個寄存器的虛擬地址對應的宏分別為S3C64XX_GPMCON、S3C64XX_GPMPUD、S3C64XX_GPMDAT。這三個宏涉及了4個頭文件共9個宏。可推出S3C64XX_GPM_BASE的值是0xF04500820,GPMCON、GPMDAT和GPMPUD寄存器的虛擬地址分別為0xF04500820、0xF04500824和0xF04500828,這三個虛擬地址是固定的,可向這三個地址寫數(shù)據(jù)。更好的是使用S3C64XX_GPMCON、S3C64XX_GPMPUD、S3C64XX_GPMDAT來操作這3個地址。一般需在LED驅動裝載時初始化上述3個寄存器。只要在leds_init()中調用leds_init_gpm()就可完成寄存器的初始化。
控制LED:LED驅動可使用兩種方式控制LED:通過字符串控制LED和通過I/O命令控制LED。要使用以上兩種方式控制LED,驅動必須接收相應的數(shù)據(jù)。若通過字符串控制LED,需使用file_operations.write(),可接收向設備文件寫入的數(shù)據(jù)。若通過I/O命令控制,需使用file_operations.ioctl(),可接收向字符設備發(fā)送的命令和參數(shù)。s3c6410_leds_write()用于接收向LED驅動的設備文件寫入控制LED的數(shù)據(jù),在實現(xiàn)其功能編寫代碼時需了解:①4個LED的亮滅用一個長度為4的mem數(shù)組。1表示點亮LED,0表示熄滅LED。與GPMDAT寄存器的低4位表示的含義正好相反②若寫入的字符串長度小于等于4,直接寫入這些字符串。若長度大于4,則只寫入前4個字符串。s3c6410_leds_write()要按傳入該函數(shù)的字符串長度返回,否則系統(tǒng)會調用多次該函數(shù)寫入字符串③事先mem數(shù)組已被清零,若要寫入的字符串長度小于4,則相當于后面的字符都是④向GPMDAT寄存器寫入數(shù)據(jù)之前最好先讀取GPMDAT寄存器的當前值,并通過位與、或等操作保留與本次操作無關的值⑤ioread32、iowrite32用于讀寫虛擬地址中的32位數(shù)據(jù)。使用命令
“# adb shell ‘echo 1101 》 /dev/s3c6410_leds’
# adb shell ‘echo 1 》 /dev/s3c6410_leds’”可通過字符串控制LED的亮、滅。I/O命令無法使用命令行方式進行測試。
LED驅動的模塊參數(shù):若想在裝載LED驅動時指定默認狀態(tài)值,就要使用模塊參數(shù)。為Linux驅動指定一個模塊參數(shù)需使用module_param(name,type,perm)宏。name表示參數(shù)名,type表示參數(shù)類型,perm表示讀/寫權限。module_param支持的參數(shù)類型包括byte、short、ushort、int、uint、long、charp、bool和invbool。使用module_param宏指定模塊參數(shù)時,會在/sys/module目錄下生成和驅動設備文件同名的目錄。若在裝載Linux驅動時未指定某個參數(shù),則參數(shù)文件的內容是該參數(shù)在Linux驅動源代碼中指定的默認值。通過module_param宏可指定參數(shù)文件的訪問權限。S_IRUGO表示所有的用戶都可訪問該參數(shù)文件中的內容,但不能修改。S_IRUGO|S_IWUSR表示允許所有用戶讀,以及創(chuàng)建文件的用戶寫。Linux內核還提供了更多的定義訪問權限的宏。S_IRWXUGO表示所有用戶可對文件讀、寫和執(zhí)行。IWUGO表示所有用戶對文件只有寫權限。需要修改LED驅動的代碼,為LED驅動添加一個模塊參數(shù),該參數(shù)存儲了4個LED的初始狀態(tài),參數(shù)類型為int。參數(shù)值的范圍是0到15.參數(shù)值控制LED的規(guī)則與GPMDAT寄存器低4位控制LED的規(guī)則相同。為LED驅動添加模塊參數(shù)首先要定義一個保存模塊參數(shù)值的變量,然后使用module_param宏指定模塊參數(shù)的相關信息。最后修改leds_init()代碼,將leds_init_gpm()的參數(shù)值改成~leds_state。使用命令“# adb shell insmod /data/local/s3c6410_leds.ko leds_state=3”可測試LED驅動的模塊參數(shù)。執(zhí)行完命令后,會在/sys/module/s3c6410_leds/parameters目錄下生成一個leds_state文件,使用命令
“# adb shell cat /sys/module/s3c6410_leds/parameters/leds_state”可看到文件內容為3。使用命令“# adb shell ‘echo 5 》 /sys/module/s3c6410_leds/parameters/leds_state’”可將文件內容改為5。修改leds_state文件內容后,在LED驅動代碼中的leds_state變量值會變成5。Linux驅動在裝載時會將指定的參數(shù)值寫入?yún)?shù)文件,若未指定參數(shù)值,Linux驅動會將參數(shù)的默認值寫入?yún)?shù)文件。在Linux驅動工作的過程中,參數(shù)值會與參數(shù)文件中的內容同步。使用module_param_array(name,type,nump,perm)宏可為Linux驅動指定數(shù)組形式的模塊參數(shù)。nump表示存儲數(shù)組長度的變量的指針,perm表示參數(shù)文件的訪問權限。通過命令“# adb shell insmod /data/local/s3c6410_leds.ko ‘leds_state=11 param=str1,str2,str3’”可指定params參數(shù)值。如果params參數(shù)指定的值的個數(shù)少于數(shù)組長度,后面的數(shù)組元素使用默認值。如果大于數(shù)組長度,LED驅動裝載失敗,并在日志中輸出信息。使用模塊參數(shù)要注意:①通過module_param_array宏的第3個參數(shù)指定數(shù)組長度時要使用指針類型的數(shù)據(jù)②如果Linux驅動含有多個模塊參數(shù),需將這些參數(shù)用單引號或雙引號括起來③指定數(shù)組類型的參數(shù)值時,逗號前不能有空格。
結語
關于使用繼電器的發(fā)光二極管閃爍電路就介紹就到這了,如有不足之處歡迎指正。