天天看點

Linux之字元裝置控制Linux之字元裝置控制

Linux之字元裝置控制

一、入口 main 函數的參數

雖然所有人都學習過 C 語言,但是對 C 語言中的 main 函數的用法并不是很清楚。由于後面的實驗需要用到這部分知識,這裡就占用一個小節,先簡單介紹一下 main 函數。

1、main 函數簡介

main 函數作為應用程式的入口,在頭檔案“#include<stdio.h> ”中。

main 函數需要傳參數的時候完整的定義為

int main(int argc,char **argv)
//參數 argc,表示參數的個數
//參數**argv,存儲輸入字元的數組
//argv[0]表示程式名稱
//argv[1]——argv[n]輸入的參數
           

不傳參數的時候定義為

函數 main 的傳回值為類型為 int,用于判斷程式執行成功還是失敗

2、main 函數例程

編寫簡單的 argvc.c 檔案測試 main 函數。

代碼如下所示,将輸入的參數第一個和第二個轉換成 int 類型,指派給 i 和 j,最後輸出列印。其中 argv[0]為程式名稱,這裡就是後面要編譯的目标檔案“argvc”。

#include<stdio.h> 
#include<string.h>

//argument count變元計數
//argument value變元值
int main(int argc,char *argv[])
{
	int i,j;
	i = atoi(argv[1]);
	j = atoi(argv[2]);
	
	printf("the Program name is %s\n",argv[0]);
	
	printf("The command line has %d argument:\n",argc-1);
	
	printf("%d,%d\n",i,j);
	
	return 0;
}
           

編譯成可執行的檔案argvc,拷貝到 U 盤,啟動最小Linux系統,插入 U 盤,加載 U 盤,運作程式如下。

Linux之字元裝置控制Linux之字元裝置控制

如上圖所示,程式成功運作,列印:

the Program name is ./mnt/udisk/argvc。因為運作的程式是“./mnt/udisk/argvc”,這是第一個參數

The command line has 2 argument:輸入的個數有兩個。

10,11。輸入的參數是 10 和 11,對應 argv[1]和 argv[2]。

二、字元類 led 燈

1、led燈簡介

在前面介紹 open 函數的時候,已經提到過如何打開字元類裝置,獲得句柄的方法和一般檔案都是一樣。

由于涉及到硬體知識,這裡簡單介紹一下硬體原理,如下圖所示,led 小燈的硬體原理很簡單。

Linux之字元裝置控制Linux之字元裝置控制

如上圖所示,給 KP_COL0 和 VDD50_EN 網絡高電平,三極管 L9014 就會導通,電源 VSYS就會将電壓加到電阻 R 和 led 小燈上,小燈就會亮。

給 KP_COL0 和 VDD50_EN 網絡低電平,三極管 L9014 就會截止,形成斷路,小燈滅。

在前面介紹過,如果要給檔案進行寫操作,那麼使用的是 write 函數。對于 led 小燈的操作,使用寫函數,理論上也是可以的。但是對于 IO 口(這裡的 IO 口指的是硬體上的 IO 口,不是指 IO 檔案)的操作,Linux 專門設計了一個高效的函數 ioctl。

這個函數在頭檔案#include<unistd.h>中。

int ioctl( int fd, int request, int cmd);
//參數 fd,函數 open 傳回的句柄。
//參數 request 和參數 cmd,由核心驅動決定具體操作,例如 request 可以代表那個 IO 口,
//cmd 代表對 IO 進行什麼樣的操作,也可以反過來。具體的含義由驅動工程師在驅動中 switch決定。
//傳回值:傳回 0 成功;傳回-1,出錯。
           

2、小燈測試例程

#include <stdio.h>
//通過 main 參數傳過來的參數是 char 字元格式的,如果要傳遞給 ioctl 函數,需要用到數值轉化函數 atoi,添加了頭檔案#include <stdlib.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//由于小燈的數量和指令都是 2,是以對小燈數量和操作數進行宏定義
#define LED_NUM 2
#define LED_C 2
//cmd為0,則滅,為1,則亮;
//io為0則是靠近蜂鳴器的小燈,為1則靠近獨立按鍵的小燈
int main(int argc,char *argv[])
{
	int fd,led_num,led_c;
	char *leds = "/dev/leds";

	led_num = LED_NUM;
	led_c = LED_C;
	
	printf("argv1 is cmd;argv2 is io \n"); 
	//對傳入的參數進行判斷,超出範圍直接退出
	if (atoi(argv[1]) >= led_c) {
		printf("argv1 is 0 or 1)");
		exit(1);
	}
	if (atoi(argv[2]) >= led_num) {
		printf("argv2 is 0 or 1)");
		exit(1);
	}
	//使用ioctl函數将參數傳入核心
	if((fd = open(leds, O_RDWR|O_NOCTTY|O_NDELAY))<0)
		printf("open %s failed\n",leds);   
	else{
			ioctl(fd,atoi(argv[1]),atoi(argv[2]));
			printf("ioctl %s success\n",leds);
		}
	close(fd);
	
	return(1);
}
           

将編譯成的可執行檔案 open,拷貝到 U 盤,啟動開發闆,插入 U 盤,加載 U 盤,使用指令“./mnt/udisk/leds 0 0”運作程式如下。可以看到其中一個燈滅了。

Linux之字元裝置控制Linux之字元裝置控制

三、字元類 Buzzer 蜂鳴器

1、蜂鳴器簡介

Linux之字元裝置控制Linux之字元裝置控制

如上圖所示。

原理圖很容易了解,如果網絡 MOTOR_PWM 為高電平,則 L9014 導通,蜂鳴器響,如果網絡 MOTOR_PWM 為低電平,則 L9014 截止,蜂鳴器則不響。

操作方式和 led 小燈類似。

2、蜂鳴器測試例程

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define BUZZER_C 2
int main(int argc,char *argv[]){
	char *buzzer_ctl = "/dev/buzzer_ctl";
	int fd,ret,buzzer_c;
	
	buzzer_c = BUZZER_C;
	
	if(atoi(argv[1]) >= buzzer_c ){
		printf("argv[1] is 0 or 1\n");
		exit(1);
	}
	
	if((fd = open(buzzer_ctl,O_RDWR|O_NOCTTY|O_NDELAY))<0){
		printf("open %s failed\n",buzzer_ctl);
		exit(1);
	}
	
	ret = ioctl(fd,atoi(argv[1]),atoi(argv[2]));
	close(fd);
	
	return 0;
}
           

将編譯成的可執行檔案 buzzertest,拷貝到 U 盤,啟動開發闆,插入 U 盤,加載 U 盤,使用參數 1 和 0,蜂鳴器會響。第二個參數實際上并不起作用(隻有一個IO口,不需要判斷)。運作程式如下。

Linux之字元裝置控制Linux之字元裝置控制

四、字元類 ADC 模數轉換

1、ADC 模數轉換簡介

Linux之字元裝置控制Linux之字元裝置控制

如上圖所示。

XadcAIN0 網絡可以讀取到目前輸入電壓,滑動變阻器 R 移動的時候,1 和 2 之間的電阻R12 改變,滑動變阻器最大電阻為 R13,然後電壓

Vadc=R12VDD1V8_EXT/R13

上面公式中 Vadc 可以通過 4412 讀取出來,VDD1V8 和 R13 已知,那麼就很容易求出 R12的電阻。如下圖所示,在 4412datasheet 中 ADC 章節中有真實的電阻和電壓曲線圖。

Linux之字元裝置控制Linux之字元裝置控制

這裡将數值做一個簡單的換算,

1.8V 對應的是 10K 歐姆,對應的寄存器數值為 0xfff;

0V 對應的是 0 歐姆,對應的寄存器數值為 0x0。

這樣做一個簡單公式,将讀取的數值 r 轉化為電阻值 R。

R = r10000/0xfff,即 R = r*10000/4095。

這個小公式在後面的代碼中将會使用到。

2、模數轉換例程

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>
#include <termios.h>

int main(void){
	int fd;
	char *adc = "/dev/adc";
	char buffer[512];
	int len=0, r=0;
	
	memset(buffer,0,sizeof(buffer));
		printf("adc ready!\n");
	
	if((fd = open(adc, O_RDWR|O_NOCTTY|O_NDELAY))<0)
		printf("open adc err!\n");
	else{
		printf("open adc success!\n");
		
		len=read(fd,buffer,10);	
		
		if(len == 0)
			printf("return null\n");
		else{
			r = atoi(buffer);
			r = (int)(r*10000/4095);	//Datas  transition to Res
			printf("res value is %d\n",r);
		}			
	}
}
           

将編譯成的可執行檔案ADC,拷貝到 U 盤,啟動開發闆,插入 U 盤,加載 U 盤,運作程式如下。可檢測目前電阻值,中間的大段列印參數是多次列印寄存器的數值,在驅動實驗中再去介紹。調整滑動電阻器之後,再次使用測試程式,如下圖所示,輸出數值會有變化。

Linux之字元裝置控制Linux之字元裝置控制

繼續閱讀