IMX6ULL鼠标光标显示到oled
生活随笔
收集整理的這篇文章主要介紹了
IMX6ULL鼠标光标显示到oled
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
獲取鼠標的坐標信息,并在oled上對應位置顯示光標。按下鼠標左鍵,oled不清屏顯示鼠標軌跡。按下鼠標右鍵,清屏并不顯示鼠標軌跡。
1、首先完成oled的驅動,采用的是0.96寸的oled屏幕,通過spi控制。
通過pinctrl子系統定義引腳
&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_hog_1>;imx6ul-evk {pinctrl_ecspi3: ecspi3grp{fsl,pins = <MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20 0x10b0 /* CS */MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK 0x10b1 /* SCLK */MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO 0x10b1 /* MISO */MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI 0x10b1 /* MOSI */>;};pinctrl_oled96_reset: oled96resetgrp {fsl,pins = </* used for oled96 reset */MX6UL_PAD_UART3_TX_DATA__GPIO1_IO24 0x10B0>;};pinctrl_oled96_DC: oled96dcgrp {fsl,pins = </* used for oled96 DC */MX6UL_PAD_UART3_RX_DATA__GPIO1_IO25 0x10B0>;};添加設備節點
&ecspi3 {fsl,spi-num-chipselects = <1>;cs-gpio = <&gpio1 20 GPIO_ACTIVE_LOW>;dc-gpio = <&gpio1 25 GPIO_ACTIVE_LOW>;reset-gpio = <&gpio1 24 GPIO_ACTIVE_LOW>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_ecspi3&pinctrl_oled96_reset&pinctrl_oled96_DC>;status = "okay";spidev: oled96spi@0 {compatible = "zhongjingyuan, oled96spi";spi-max-frequency = <8000000>;reg = <0>;};};編寫oled設備驅動文件
#include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/gpio.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/of_gpio.h> #include <linux/semaphore.h> #include <linux/timer.h> #include <linux/i2c.h> #include <linux/spi/spi.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/spi/spi.h>/************************************ 版本:v1.0* 描述:SSD1306 SPI驅動程序* **********************************/#define oled96_CNT 1 #define oled96_NAME "oled96spi"#define OLED_CMD 0 #define OLED_DATA 1static u8 OLED_GRAM[144][8];/* leddev 設備結構體 */ struct oled96_dev{dev_t devid; /* 設備號 */struct cdev cdev; /* cdev */struct class *class; /* 類 */struct device *device; /* 設備 */int major; /* 主設備號 */ void *private_data; /* 私有數據 */struct device_node *nd; /* 設備節點 */int cs_gpio; /* 片選GPIO編號*/int dc_gpio; /* 命令/數據選擇GPIO編號*/int reset_gpio; /* 片選所使用的GPIO編號 */ };struct oled96_dev oled96dev;/* 傳統匹配方式 ID 列表 */ static const struct spi_device_id oled96_id[] = {{"zhongjingyuan, oled96spi", 0}, {} };/* 設備樹匹配列表 */ static const struct of_device_id oled96_of_match[] = {{ .compatible = "zhongjingyuan, oled96spi" },{ /* Sentinel */ } };static int oled96_write_regs(struct oled96_dev *dev, u8 *buf, u8 len) {int ret;unsigned char txdata[len];struct spi_message m;struct spi_transfer *t;struct spi_device *spi = (struct spi_device *)dev->private_data;t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);gpio_set_value(dev->cs_gpio, 0); /* 片選拉低 */ t->tx_buf = buf; t->len = len; spi_message_init(&m); spi_message_add_tail(t, &m);ret = spi_sync(spi, &m);kfree(t); gpio_set_value(dev->cs_gpio, 1);/* 片選拉高,釋放oled96 */ return ret; }static void oled96_write_onereg(struct oled96_dev *dev, u8 value, u8 cmd) {u8 buf = value;if(cmd)gpio_set_value(dev->dc_gpio, 1);else gpio_set_value(dev->dc_gpio, 0);oled96_write_regs(dev, &buf, 1);gpio_set_value(dev->dc_gpio, 1); }static void OLED_Refresh(void) {u8 i,n;for(i=0;i<8;i++){oled96_write_onereg(&oled96dev, 0xb0+i,OLED_CMD); //設置行起始地址oled96_write_onereg(&oled96dev, 0x00,OLED_CMD); //設置低列起始地址oled96_write_onereg(&oled96dev, 0x10,OLED_CMD); //設置高列起始地址for(n=0;n<128;n++)oled96_write_onereg(&oled96dev,OLED_GRAM[n][i],OLED_DATA);} }static void OLED_Clear(void) {u8 i,n;for(i=0;i<8;i++){for(n=0;n<128;n++){OLED_GRAM[n][i]=0;//清除所有數據}}OLED_Refresh();//更新顯示 }//畫點 //x:0~127//y:0~63 static void OLED_DrawPoint(u8 x,u8 y){u8 i,m,n;i=y/8;m=y%8;n=1<<m;OLED_GRAM[x][i]|=n;}static void OLED_DrawCircle(u8 x, u8 y, u8 r) {int a, b,num;a = 0;b = r;while(2 * b * b >= r * r) {OLED_DrawPoint(x + a, y - b);OLED_DrawPoint(x - a, y - b);OLED_DrawPoint(x - a, y + b);OLED_DrawPoint(x + a, y + b);OLED_DrawPoint(x + b, y + a);OLED_DrawPoint(x + b, y - a);OLED_DrawPoint(x - b, y - a);OLED_DrawPoint(x - b, y + a);a++;num = (a * a + b * b) - r*r;//計算畫的點離圓心的距離if(num > 0){b--;a--;}} }//配置寫入數據的起始位置 static void OLED_WR_BP(u8 x,u8 y) {oled96_write_onereg(&oled96dev, 0xb0+y,OLED_CMD);//設置行起始地址oled96_write_onereg(&oled96dev, ((x&0xf0)>>4)|0x10,OLED_CMD);//設置低列起始地址oled96_write_onereg(&oled96dev, (x&0x0f)|0x01,OLED_CMD);//設置高列起始地址 }static void OLED_ShowPicture(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[]) {u32 j=0;u8 x=0,y=0;if(y%8==0)y=0;else y+=1;for(y=y0;y<y1;y++){OLED_WR_BP(x0,y);for(x=x0;x<x1;x++){oled96_write_onereg(&oled96dev, BMP[j],OLED_DATA);j++;}} }/* * @description : 打開設備 * @param – inode : 傳遞給驅動的 inode * @param - filp : 設備文件,file 結構體有個叫做 pr 似有 ate_data 的成員變量 * 一般在 open 的時候將 private_data 似有向設備結構體。 * @return : 0 成功;其他 失敗 */ static int oled96_open(struct inode *inode, struct file *filp) {filp->private_data = &oled96dev; /* 設置私有數據 */return 0; }/* * @description : 從設備讀取數據 * @param - filp : 要打開的設備文件(文件描述符) * @param - buf : 返回給用戶空間的數據緩沖區 * @param - cnt : 要讀取的數據長度 * @param - offt : 相對于文件首地址的偏移 * @return : 讀取的字節數,如果為負值,表示讀取失敗 */ static ssize_t oled96_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off) {return 0; }/* * @description : 向設備寫數據 * @param - filp : 設備文件,表示打開的文件描述符 * @param - buf : 要寫給設備寫入的數據 * @param - cnt : 要寫入的數據長度 * @param – offt : 相對于文件首地址的偏移 * @return : 寫入的字節數,如果為負值,表示寫入失敗 */ static ssize_t oled96_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) {struct mice_oled{char abs_Xpos;char abs_Ypos;char click_event;char clear;};//使用結構體write()傳參失敗//struct mice_oled *miceoled = (struct mice_oled *)buf;//databuf[0] x的絕對坐標,databuf[1] y的絕對坐標, databuf[2] 按鍵事件類型, databuf[3] 是否選擇清屏寫unsigned char databuf[4];long err = 0; struct oled96_dev *dev = (struct oled96_dev *)filp->private_data;err = copy_from_user(databuf, buf, sizeof(cnt));if(err < 0){printk("kernel write failed!\r\n");return -EFAULT;}if(databuf[3] == 0){OLED_Clear();OLED_DrawCircle(databuf[0], databuf[1], 2);}else{OLED_DrawCircle(databuf[0], databuf[1], 2);}OLED_Refresh();return 0; }/* * @description : 關閉/釋放設備 * @param - filp : 要關閉的設備文件(文件描述符) * @return : 0 成功;其他 失敗 */ static int oled96_release(struct inode *inode, struct file *filp) {return 0; }static const struct file_operations oled96_ops = {.owner = THIS_MODULE,.open = oled96_open,.read = oled96_read,.write = oled96_write,.release = oled96_release, };/* *初始化SSD1306寄存器 *移植自stm32例程的初始化,修改了函數調用 */ void oled96_reginit(struct oled96_dev *dev) { gpio_set_value(dev->reset_gpio, 1);mdelay(100);gpio_set_value(dev->reset_gpio, 0);mdelay(200);gpio_set_value(dev->reset_gpio, 1);oled96_write_onereg(&oled96dev, 0xAE,OLED_CMD);//--turn off oled paneloled96_write_onereg(&oled96dev, 0x00,OLED_CMD);//---set low column addressoled96_write_onereg(&oled96dev, 0x10,OLED_CMD);//---set high column addressoled96_write_onereg(&oled96dev, 0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)oled96_write_onereg(&oled96dev, 0x81,OLED_CMD);//--set contrast control registeroled96_write_onereg(&oled96dev, 0xCF,OLED_CMD);// Set SEG Output Current Brightnessoled96_write_onereg(&oled96dev, 0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常oled96_write_onereg(&oled96dev, 0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常oled96_write_onereg(&oled96dev, 0xA6,OLED_CMD);//--set normal displayoled96_write_onereg(&oled96dev, 0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)oled96_write_onereg(&oled96dev, 0x3f,OLED_CMD);//--1/64 dutyoled96_write_onereg(&oled96dev, 0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)oled96_write_onereg(&oled96dev, 0x00,OLED_CMD);//-not offsetoled96_write_onereg(&oled96dev, 0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequencyoled96_write_onereg(&oled96dev, 0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Secoled96_write_onereg(&oled96dev, 0xD9,OLED_CMD);//--set pre-charge periodoled96_write_onereg(&oled96dev, 0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clockoled96_write_onereg(&oled96dev, 0xDA,OLED_CMD);//--set com pins hardware configurationoled96_write_onereg(&oled96dev, 0x12,OLED_CMD);oled96_write_onereg(&oled96dev, 0xDB,OLED_CMD);//--set vcomholed96_write_onereg(&oled96dev, 0x40,OLED_CMD);//Set VCOM Deselect Leveloled96_write_onereg(&oled96dev, 0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)oled96_write_onereg(&oled96dev, 0x02,OLED_CMD);//oled96_write_onereg(&oled96dev, 0x8D,OLED_CMD);//--set Charge Pump enable/disableoled96_write_onereg(&oled96dev, 0x14,OLED_CMD);//--set(0x10) disableoled96_write_onereg(&oled96dev, 0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)oled96_write_onereg(&oled96dev, 0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) oled96_write_onereg(&oled96dev, 0xAF,OLED_CMD);OLED_Clear(); }/* * @description : spi 驅動的 probe 函數,當驅動與 * 設備匹配以后此函數就會執行 * @param - client : spi 設備 * @param - id : spi 設備 ID */ static int oled96_probe(struct spi_device *spi) {int ret;/* 1、構建設備號 */if (oled96dev.major) {oled96dev.devid = MKDEV(oled96dev.major, 0);register_chrdev_region(oled96dev.devid, oled96_CNT, oled96_NAME);} else {alloc_chrdev_region(&oled96dev.devid, 0, oled96_CNT, oled96_NAME);oled96dev.major = MAJOR(oled96dev.devid);}/* 2、注冊設備 */cdev_init(&oled96dev.cdev, &oled96_ops);cdev_add(&oled96dev.cdev, oled96dev.devid, oled96_CNT);/* 3、創建類 */oled96dev.class = class_create(THIS_MODULE, oled96_NAME);if (IS_ERR(oled96dev.class)) {return PTR_ERR(oled96dev.class);}/* 4、創建設備 */oled96dev.device = device_create(oled96dev.class, NULL, oled96dev.devid, NULL, oled96_NAME);if (IS_ERR(oled96dev.device)) {return PTR_ERR(oled96dev.device);}/*獲取spi設備節點*/oled96dev.nd = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000");if(oled96dev.nd == NULL){printk("\r\necspi3 node not find! \r\n");return -EINVAL;}/*獲取GPIO信息*/oled96dev.cs_gpio = of_get_named_gpio(oled96dev.nd, "cs-gpio", 0);if(oled96dev.cs_gpio < 0){printk("can't get cs-gpio\r\n");return -EINVAL;} oled96dev.reset_gpio = of_get_named_gpio(oled96dev.nd, "reset-gpio", 0);if(oled96dev.reset_gpio < 0) {printk("can't get reset-gpio");return -EINVAL;}oled96dev.dc_gpio = of_get_named_gpio(oled96dev.nd, "dc-gpio", 0);if(oled96dev.dc_gpio < 0){printk("can't get dc-gpio\r\n");return -EINVAL;} //輸出GPIOret = gpio_direction_output(oled96dev.cs_gpio, 1);if(ret < 0){printk("can't set cs-gpio\r\n");}ret = gpio_direction_output(oled96dev.dc_gpio, 1);if(ret < 0){printk("can't set dc-gpio\r\n");}ret = gpio_direction_output(oled96dev.reset_gpio, 1);if(ret < 0) {printk("can't set res gpio!\r\n");}/*初始化 spi_device */spi->mode = SPI_MODE_0; /*MODE0,CPOL=0,CPHA=0*/spi_setup(spi);oled96dev.private_data = spi; /* 設置私有數據 *//* 初始化SSD1306 內部寄存器 */oled96_reginit(&oled96dev);OLED_DrawCircle(30,30,20);OLED_Refresh();printk("show a Circle\r\n");return 0; }/* * @description : spi 驅動的 remove 函數,移除spi 驅動的時候此函數會執行 * @param - client : spi 設備 * @return : 0,成功;其他負值,失敗 */ static int oled96_remove(struct spi_device *spi) {/* 刪除設備 */cdev_del(&oled96dev.cdev);unregister_chrdev_region(oled96dev.devid, oled96_CNT);/* 注銷掉類和設備 */device_destroy(oled96dev.class, oled96dev.devid);class_destroy(oled96dev.class);return 0; }/* SPI 驅動結構體 */ static struct spi_driver oled96_driver = {.probe = oled96_probe,.remove = oled96_remove,.driver = {.owner = THIS_MODULE,.name = "oled96spi",.of_match_table = oled96_of_match, },.id_table = oled96_id, };/* * @description : 驅動入口函數 * @param : 無 * @return : 無 */ static int __init oled96_init(void) {return spi_register_driver(&oled96_driver); }/* * @description : 驅動出口函數 * @param : 無 * @return : 無 */ static void __exit oled96_exit(void) {spi_unregister_driver(&oled96_driver); }module_init(oled96_init); module_exit(oled96_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("cr");2、usb鼠標對應驅動在linux內核中已經支持,通過編譯內核選項選擇是否編譯。
linux中鍵盤鼠標等輸入設備通過input子系統實現設備驅動,驅動程序完成向系統報告輸入事件,input子系統完成了文件操作接口。進入/dev/input目錄下,查看新增的文件。
mouse_fd = open(DEV_MOUSE, O_RDONLY);
read(mouse_fd, data, sizeof(data));
data 數組的第0個字節:bit 0、1、2、3、4分別代表左、右、中、SIDE、EXTRA鍵的按下情況; ?
data 數組的第1個字節:表示鼠標的相對水平位移; ?
data 數組的第2個字節:表示鼠標的相對垂直位移; ?
data 數組的第3個字節:REL_WHEEL位移。 ?
data 數組的第4個字節:中間滾輪事件。 ??
/* 調用oledspi驅動,顯示鼠標方位 使用結構體write()傳參失敗*/#include <stdio.h> #include <errno.h> #include <fcntl.h> #include <sys/select.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h>#define DEV_MOUSE "/dev/input/mouse0" #define DEV_OLEDSPI "/dev/oled96spi" #define EVENT_MOUSEI "dev/input/event1"struct mice_oled{char abs_Xpos;char abs_Ypos;char click_event;char clear; };int main(void) {int mouse_fd,oled96spi_fd;int ret,i;signed char rel_position_pre[3];signed char rel_position_now[3];//1 x絕對位置;2 y絕對位置;3 按鍵事件; 4 清屏命令signed char miceoled_dev[4] = {64, 32, 0, 0};struct mice_oled miceoled; miceoled.abs_Xpos = 64;miceoled.abs_Ypos = 32;mouse_fd = open(DEV_MOUSE, O_RDONLY);if(mouse_fd < 0){perror("mouse file open failed");_exit(-1);}oled96spi_fd = open(DEV_OLEDSPI, O_RDWR);if(oled96spi_fd < 0){close(mouse_fd);perror("oled file open failed");_exit(-1);}while(1){for(i=0; i<sizeof(rel_position_now); i++){rel_position_pre[i] = rel_position_now[i];}//讀取mouse事件數據ret = read(mouse_fd, rel_position_now, sizeof(rel_position_now));if(-1 == ret ){perror("read file is failed");close(mouse_fd);close(oled96spi_fd);_exit(-1);}miceoled_dev[2] = rel_position_now[0];/*如果相對位置數據有變化,就打印出來并且在oled上刷新顯示出來 */for(i=0; i<sizeof(rel_position_now); i++){if(rel_position_pre[i] != rel_position_now[i]){//確定x的絕對位置if(rel_position_now[1]<0){miceoled_dev[0] = miceoled_dev[0] + rel_position_now[1]/4;if(miceoled_dev[0] <= 1){//printf("x less 0\r\n");miceoled_dev[0] = 2;}}if(rel_position_now[1]>0){miceoled_dev[0] = miceoled_dev[0] + rel_position_now[1]/5;if(miceoled_dev[0] < 0){//printf("x exceed 127\r\n");miceoled_dev[0] = 127;}}//確定y的絕對位置miceoled_dev[1] = miceoled_dev[1] - rel_position_now[2]/4;if(miceoled_dev[1] <= 2){//printf("y less 0\r\n");miceoled_dev[1] = 2;}else if (miceoled_dev[1] >= 63){//printf("y exceed 63\r\n");miceoled_dev[1] = 63; }//判斷鼠標是否按下if((miceoled_dev[2]&15) == 10){miceoled_dev[3] = 0;}else if((miceoled_dev[2]&15) == 9){ miceoled_dev[3] = 1;}ret = write(oled96spi_fd, miceoled_dev, sizeof(miceoled_dev));if(ret < 0){printf("oled Control Failed!\r\n");close(mouse_fd);close(oled96spi_fd);return -1;}printf("x is: %d, y is: %d\r\n", miceoled_dev[0], miceoled_dev[1]);//printf("rel_x is: %d, rel_y is: %d\r\n", rel_position_now[1], rel_position_now[2]);printf("click value: %d\r\n",miceoled_dev[2]&15);break;}} }close(mouse_fd);close(oled96spi_fd);return 0; }?注意的問題,在交叉編譯器中,char類型定義的是默認無符號型的char類型,使用signed char定義有符號類型
總結
以上是生活随笔為你收集整理的IMX6ULL鼠标光标显示到oled的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 实现大文本文件切割
- 下一篇: Juniper 防火墙端口映射