DS18B20驅動編寫–雜項設備框架注冊
設備驅動最通俗的解釋就是“驅使硬件設備行動”。驅動與底層硬件直接打交道,按照硬件設備的具體工作方式,讀寫設備的寄存器,完成設備的輪詢、中斷處理、DMA通信,進行物理內存向虛擬內存的映射等,最終讓通信設備能收發(fā)數據,讓顯示設備能顯示文字和畫面,讓存儲設備能記錄文件和數據。
驅動程序是應用層和硬件層的連接橋梁,應用層只管完成應用邏輯開發(fā)和界面設計,驅動層則處理硬件配置,實現應用層相關接口函數。
雜項設備:字符設備類的一種,雜項設備主設備號為10。
1.DS18B20簡介
DS18B20是Dallas半導體公司生產的數字溫度傳感器,是世界上第一片支持"一線總線"接口的溫度傳感器。測量溫度范圍為-55℃ ~ +125℃,精度為±0.5℃。分辨率為9 ~ 12位。支持3V ~ 5.5V輸入電壓。抗干擾能力強。
每一個DSl820包括一個唯一的64位長的序號,該序號值存放在 DSl820 內部的 ROM(只讀存貯器)中。開始8位是產品類型編碼(DSl820 編碼均為 10H) ,接著的 48位是每個器件唯一的序號,最后 8 位是前面 56 位的CRC(循環(huán)冗余校驗)碼。
引腳 | 說明 |
GND | 地 |
DQ | 數字信號腳 |
VDD | 電源腳3V~5.5V |
??DS18B20以9位數字量形式反應器件的溫度值。
??DS18B20采用單總線通訊,與CPU之間只需要DQ腳相連,再和CPU之間共地即可。每一個DS18B20都有唯一的64位光刻ROM,因此可以在一根數據線上接多個DS18B20模塊。
- 單總線協議特性
- 總線協議:一個數據線可掛載多個設備(DS18B20通過64位光刻ROM區(qū)分設備);
- 半雙工通訊:數據線上同一時間只能發(fā)送或者接收數據;
2.DS18B20驅動時序
2.1 發(fā)送復位脈沖和檢測存在信號
??DS18B20初始化過程首先需要發(fā)送復位脈沖:至少480us的低電平信號。接下來釋放總線,DS18B20開始返回存在信號:60~240us的低電平。最后釋放總線,模塊初始化完成。
/*發(fā)送復位信號,檢測存在脈沖*/
static u8 ds18b20_CheckRst(void)
{
u8 time=0;
DS18B20_OUT_MODE();/*輸出模式*/
DS18B20_OUT(0);/*總線拉低*/
udelay(600);/*至少480us低電平*/
DS18B20_OUT(1);/*釋放總線,恢復為空閑電平*/
udelay(15);
DS18B20_INPUT_MODE();/*輸入模式*/
while(DS18B20_IN)
{
time++;
udelay(1);
if(time>=100)return 1;/*等待存在脈沖失敗*/
}
time=0;
while(!DS18B20_IN)
{
time++;
udelay(1);
if(time>=250)return 2;//模塊出錯
}
return 0;
}
2.2 寫一位數據時序
??要實現寫一字節(jié)數據,則首先要實現的是寫一位數據時序。分為寫1和寫0。首先是總線拉低,產生寫間隙(至少1us)。接著往數據線DQ上寫入0或者1,周期時間為60us,最后釋放總線(總線拉高,至少1us),至此,寫數據完成。
DS18B20_OUT_MODE();/*輸出模式*/
DS18B20_OUT(0);//總線拉低,產生寫間隙時間
udelay(2);
if(dat&0x01)DS18B20_OUT(1);
else DS18B20_OUT(0);
udelay(60);//寫周期時間
DS18B20_OUT(1);//釋放總線
udelay(2);
dat>>=1;//繼續(xù)發(fā)送下一位數據
2.3 讀一位數據時序
??讀數據首先需要主機產生讀間隙:總線拉低,至少1us的低電平信號。接著釋放總線,在15us內進行數據讀取,讀數據周期時間為60us,最后釋放總線:總線拉高,至少1us時間。 至此,讀一位數據完成。
DS18B20_OUT_MODE();/*輸出模式*/
DS18B20_OUT(0);//總線拉低,產生讀間隙時間
udelay(2);
DS18B20_INPUT_MODE();//配置為輸入模式
udelay(12);//等待數據到來
data>>=1;
if(DS18B20_IN)data|=0x80;
udelay(50);//讀數據時間
DS18B20_OUT(1);//恢復總線為空閑電平
udelay(2);
3.DS18B20相關命令
- 跳轉指令0xCC
這條指令允許控制器不需要提供64位光刻ROM就使用存儲器操作命令,在總線上僅有一個DS18B20時使用,若有多個則會產生沖突。
- 啟動一次溫度轉換0x44
此命令完成一次溫度轉換。執(zhí)行此命令后,DS18B20保持等待狀態(tài)。若總線在這條命令發(fā)送后跟著讀間隙,而DS18B20正處于數據轉換,則會輸出一個0,若溫度轉換完成,則會輸出1。若使用寄生電源,總線必須在這條命令發(fā)完后拉高總線,保存500ms。
- 讀取一次數據0xBE
此命令用于讀取暫存器中的內容,可連續(xù)讀取9個字節(jié)數據。若只想讀取溫度數據,則只需要讀取前兩個字節(jié)即可。
- 讀ROM 0x33
此命令可以讀取DS18B20的64位光刻ROM數據,此命令僅能在總線上一個設備的時候使用。
- 匹配ROM 0x55
此命令可以實現和DS18B20的ROM進行匹配,只有和DS1820的64位光刻ROM完全匹配才能響應后面存儲器命令。此命令用于當總線上不止一個設備時使用。
- 搜索ROM 0xF0
當系統第一次啟動時,無法確認總線上有多少個設備或者該設備的光刻ROM,搜索光刻ROM可以讓控制器通過排除法識別總線上的所有設備的64位光刻ROM。
4.DS18B20采集一次溫度步驟
??采用外部電源供電,且總線上僅有一個DS18B20模塊。
5.編寫DS18B20驅動,通過雜項設備注冊
- 開發(fā)平臺
開發(fā)平臺:Ubuntu18.04
編譯器:arm-linux-gcc
硬件平臺:tiny4412基于Cortex-A9 4核1.5GHZ
開發(fā)板內核:Linux3.5
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static unsigned int ds18b20_gpio=EXYNOS4_GPB(4);//GPB_4
#define DS18B20_OUT_MODE() s3c_gpio_cfgpin(ds18b20_gpio,S3C_GPIO_OUTPUT)/*輸出模式*/
#define DS18B20_INPUT_MODE() s3c_gpio_cfgpin(ds18b20_gpio,S3C_GPIO_INPUT)/*輸入模式*/
#define DS18B20_OUT(x) gpio_set_value(ds18b20_gpio,(x))
#define DS18B20_IN gpio_get_value(ds18b20_gpio)
/*發(fā)送復位信號,檢測存在脈沖*/
static u8 ds18b20_CheckRst(void)
{
u8 time=0;
DS18B20_OUT_MODE();/*輸出模式*/
DS18B20_OUT(0);/*總線拉低*/
udelay(600);/*至少480us低電平*/
DS18B20_OUT(1);/*釋放總線,恢復為空閑電平*/
udelay(15);
DS18B20_INPUT_MODE();/*輸入模式*/
while(DS18B20_IN)
{
time++;
udelay(1);
if(time>=100)return 1;/*等待存在脈沖失敗*/
}
time=0;
while(!DS18B20_IN)
{
time++;
udelay(1);
if(time>=250)return 2;//模塊出錯
}
return 0;
}
/*寫一個字節(jié)函數*/
static void ds18b20_writeDat(u8 dat)
{
int i=0;
DS18B20_OUT_MODE();/*輸出模式*/
for(i=0;i<8;i++)
{
DS18B20_OUT(0);//總線拉低,產生寫間隙時間
udelay(2);
if(dat&0x01)DS18B20_OUT(1);
else DS18B20_OUT(0);
udelay(60);//寫周期時間
DS18B20_OUT(1);//釋放總線
udelay(2);
dat>>=1;//繼續(xù)發(fā)送下一位數據
}
}
/*讀取1字節(jié)數據*/
static u8 ds18b20_readDat(void)
{
int i=0;
u8 data=0;
for(i=0;i<8;i++)
{
DS18B20_OUT_MODE();/*輸出模式*/
DS18B20_OUT(0);//總線拉低,產生讀間隙時間
udelay(2);
DS18B20_INPUT_MODE();//配置為輸入模式
udelay(12);//等待數據到來
data>>=1;
if(DS18B20_IN)data|=0x80;
udelay(50);//讀數據時間
DS18B20_OUT(1);//恢復總線為空閑電平
udelay(2);
}
return data;
}
/*獲取一次溫度數據*/
static u16 ds18b20_GetTemp(void)
{
u8 L,H;
u16 temp;
if(ds18b20_CheckRst())return 0xffff;
ds18b20_writeDat(0xcc);
ds18b20_writeDat(0x44);
while(ds18b20_readDat()!=0xff);/*等待溫度轉換完成*/
if(ds18b20_CheckRst())return 0xffff;
ds18b20_writeDat(0xcc);
ds18b20_writeDat(0xbe);/*讀取一次溫度*/
L=ds18b20_readDat();
H=ds18b20_readDat();
temp=H<<8|L;
return temp;
}
static int ds18b20_open(struct inode *inode, struct file *file)
{
printk("open函數調用成功\n");
if(ds18b20_CheckRst())
{
printk("DS18B20初始化失敗\n");
}
return 0;
}
static int ds18b20_release(struct inode *inode, struct file *file)
{
printk("release函數調用成功");
return 0;
}
long ds18b20_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int dir=_IOC_DIR(cmd);/*數據讀寫方向,00無參數,10用戶層讀,01用戶層寫,11可讀寫*/
int type=_IOC_TYPE(cmd);/*魔術,標志符*/
int size=_IOC_SIZE(cmd);/*arg的字節(jié)數*/
printk("dir=%d,type=%c,size=%d\n",dir,type,size);
int ret;
u16 temp=ds18b20_GetTemp();/*獲取一次溫度*/
ret=copy_to_user((void *)arg, &temp,size);
return 4-ret;
}
static struct file_operations ds18b20_fops=
{
.open =ds18b20_open,
.release =ds18b20_release,
.unlocked_ioctl =ds18b20_ioctl
};
/*雜項設備結構體*/
static struct miscdevice ds18b20_drv=
{
.minor =MISC_DYNAMIC_MINOR,/*255,有內核自動分配*/
.name ="ds18b20",//設備節(jié)點名字
.fops =&ds18b20_fops,//文件操作集合
};
static int __init wbyq_ds18b20_init(void)
{
/*1.GPIO注銷*/
gpio_free(ds18b20_gpio);
/*2.注冊GPIO*/
gpio_request(ds18b20_gpio,"DS18B20");
/*配置GPIO模式*/
s3c_gpio_cfgpin(ds18b20_gpio,S3C_GPIO_OUTPUT);
gpio_set_value(ds18b20_gpio,1);/*上拉*/
/*注冊雜項設備*/
misc_register(&ds18b20_drv);
return 0;
}
/*驅動釋放*/
static void __exit wbyq_ds18b20_cleanup(void)
{
printk("驅動出口,驅動注銷成功\n");
/*注銷雜項設備*/
misc_deregister(&ds18b20_drv);
/*注銷GPIO*/
gpio_free(ds18b20_gpio);
}
module_init(wbyq_ds18b20_init);//驅動入口函數
module_exit(wbyq_ds18b20_cleanup);//驅動出口函數
MODULE_LICENSE("GPL");//驅動注冊協議
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 ds18b20 Driver");
審核編輯:湯梓紅
-
溫度傳感器
+關注
關注
48文章
2918瀏覽量
155899 -
DS18B20
+關注
關注
10文章
778瀏覽量
80717 -
設備驅動
+關注
關注
0文章
68瀏覽量
10879
發(fā)布評論請先 登錄
相關推薦
評論