linux pwm 調屏_Linux驅動學習之:PWM驅動

PWM(Pulse Width Modulation)——脈寬調制,它是利用微控制器的數字輸出來對模擬電路進行控制的一種非常有效的技術,廣泛應用于測量、通信、功率控制與變換等許多領域。

s3c2440芯片中一共有5個16位的定時器,其中有4個定時器(定時器0~定時器3)具有脈寬調制功能,因此用s3c2440可以很容易地實現PWM功能。載有s3c2440芯片的Mini2440 板子帶有一個蜂鳴器,它是由 PWM 控制的,下面是它的連接原理圖:

操控PWM主要分以下四步:

1、PWM是通過引腳TOUT0~TOUT3輸出的,而這4個引腳是與GPB0~GPB3復用的,因此要實現PWM功能首先要把相應的引腳配置成TOUT輸出。

2、再設置定時器的輸出時鐘頻率,它是以PCLK為基準,再除以用寄存器TCFG0配置的prescaler參數,和用寄存器TCFG1配置的divider參數。

3、然后設置脈沖的具體寬度,它的基本原理是通過寄存器TCNTBn來對寄存器TCNTn(內部寄存器)進行配置計數,TCNTn是遞減的,如果減到零,則它又會重新裝載TCNTBn里的數,重新開始計數,而寄存器TCMPBn作為比較寄存器與計數值進行比較,當TCNTn等于TCMPBn時,TOUTn輸出的電平會翻轉,而當TCNTn減為零時,電平會又翻轉過來,就這樣周而復始。因此這一步的關鍵是設置寄存器TCNTBn和TCMPBn,前者可以確定一個計數周期的時間長度,而后者可以確定方波的占空比。由于s3c2440的定時器具有雙緩存,因此可以在定時器運行的狀態下,改變這兩個寄存器的值,它會在下個周期開始有效。

4、最后就是對PWM的控制,它是通過寄存器TCON來實現的,一般來說每個定時器主要有4個位要配置(定時器0多一個死區位):啟動/終止位,用于啟動和終止定時器;手動更新位,用于手動更新TCNTBn和TCMPBn,這里要注意的是在開始定時時,一定要把這位清零,否則是不能開啟定時器的;輸出反轉位,用于改變輸出的電平方向,使原先是高電平輸出的變為低電平,而低電平的變為高電平;自動重載位,用于TCNTn減為零后重載TCNTBn里的值,當不想計數了,可以使自動重載無效,這樣在TCNTn減為零后,不會有新的數加載給它,那么TOUTn輸出會始終保持一個電平(輸出反轉位為0時,是高電平輸出;輸出反轉位為1時,是低電平輸出),這樣就沒有PWM功能了,因此這一位可以用于停止PWM。

因此,我們需要在驅動程序中,按照上述的操控序列就可以控制 PWM 的輸出頻率了。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define DEVICE_NAME "pwm" //設備名

#define PWM_IOCTL_SET_FREQ 1 //定義宏變量,用于后面的 ioctl 中的控制命令

#define PWM_IOCTL_STOP 0???? //定義宏變量,用于后面的 ioctl 中的控制命令

//定義信號量 lock用于互斥,因此,改驅動程序只能同時有一個進程使用

static struct semaphore lock;

/* freq: pclk/50/16/65536 ~ pclk/50/16

* if pclk = 50MHz, freq is 1Hz to 62500Hz

* human ear : 20Hz~ 20000Hz

*/

//設置 pwm 的頻率,配置各個寄存器

static void PWM_Set_Freq( unsigned long freq )

{

unsigned long tcon;

unsigned long tcnt;

unsigned long tcfg1;

unsigned long tcfg0;

struct clk *clk_p;

unsigned long pclk;

//set GPB0 as tout0, pwm output 設置 GPB0 為 tout0,pwm 輸出

s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);

tcon = __raw_readl(S3C2410_TCON); //讀取寄存器 TCON 到 tcon

tcfg1 = __raw_readl(S3C2410_TCFG1); //讀取寄存器 TCFG1 到 tcfg1

tcfg0 = __raw_readl(S3C2410_TCFG0); //讀取寄存器 TCFG0 到 tcfg0

//設置TCFG0寄存器,prescaler = 50

tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; // S3C2410_TCFG_PRESCALER0_MASK 定時器 0 和1 的預分頻值的掩碼,清除TCFG[0~8]

tcfg0 |= (50 - 1); // 設置預分頻為 50

//設置TCFG1寄存器,mux = 1/16

tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; //S3C2410_TCFG1_MUX0_MASK 定時器 0 分割值的掩碼:清除TCFG1[0~3]

tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; //定時器 0 進行 16 分割

__raw_writel(tcfg1, S3C2410_TCFG1); //把 tcfg1 的值寫到分割寄存器 S3C2410_TCFG1 中

__raw_writel(tcfg0, S3C2410_TCFG0); //把 tcfg0 的值寫到預分頻寄存器 S3C2410_TCFG0 中

clk_p = clk_get(NULL, "pclk"); //得到 pclk

pclk = clk_get_rate(clk_p);

tcnt = (pclk/50/16)/freq; //得到定時器的輸入時鐘,進而設置 PWM 的調制頻率

__raw_writel(tcnt, S3C2410_TCNTB(0)); //PWM 脈寬調制的頻率等于定時器的輸入時鐘,確定一個計數周期的時間長度

__raw_writel(tcnt/2, S3C2410_TCMPB(0)); //占空比是 50%

tcon &= ~0x1f;??? //清空低5位,其中:TCON[4] --Dead zone enable, TCON[3] -- Timer 0 auto reload on/off, TCON[2] -- Timer 0 output inverter on/off, TCON[1] -- Timer 0 manual update, TCON[0] -- Timer 0 start/stop????? /*

* 0xb: 0000 1011

* disable dead zone, auto reload for Timer 0, output inverter off, Update TCNTB0&TCMPB0, start for Timer 0

*/

tcon |= 0xb;

__raw_writel(tcon, S3C2410_TCON); //把 tcon 寫到計數器控制寄存器 S3C2410_TCON 中

tcon &= ~2;?? //clear manual update bit

__raw_writel(tcon, S3C2410_TCON);

}

static void PWM_Stop(void)

{

s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT); //設置 GPB0 為輸出

s3c2410_gpio_setpin(S3C2410_GPB(0), 0); //設置 GPB0 為低電平,使蜂鳴器停止

}

static int s3c24xx_pwm_open(struct inode *inode, struct file *file)

{

if (!down_trylock(&lock)) //是否獲得信號量,是 down_trylock(&lock)=0,否則非 0

return 0;

else

return -EBUSY; //返回錯誤信息:請求的資源不可用

}

static int s3c24xx_pwm_close(struct inode *inode, struct file *file)

{

PWM_Stop();

up(&lock); //釋放信號量 lock

return 0;

}

/*cmd 是 1,表示設置頻率;cmd 是 2 ,表示停止 pwm*/

static int s3c24xx_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

{

switch (cmd) {

case PWM_IOCTL_SET_FREQ: //if cmd=1 即進入 case PWM_IOCTL_SET_FREQ

if (arg == 0) //如果設置的頻率參數是 0

return -EINVAL; //返回錯誤信息,表示向參數傳遞了無效的參數

PWM_Set_Freq(arg); //否則設置頻率

break;

case PWM_IOCTL_STOP: // if cmd=2 即進入 case PWM_IOCTL_STOP

PWM_Stop(); //停止蜂鳴器

break;

}

return 0; //成功返回

}

/*初始化設備的文件操作的結構體*/

static struct file_operations dev_fops = {

.owner = THIS_MODULE,

.open = s3c24xx_pwm_open,

.release = s3c24xx_pwm_close,

.ioctl = s3c24xx_pwm_ioctl,

};

static struct miscdevice misc = {

.minor = MISC_DYNAMIC_MINOR,

.name = DEVICE_NAME,

.fops = &dev_fops,

};

static int __init dev_init(void)

{

int ret;

init_MUTEX(&lock); //初始化一個互斥鎖

ret = misc_register(&misc); //注冊一個 misc 設備

printk (DEVICE_NAME"\tinitialized\n");

return ret;

}

static void __exit dev_exit(void)

{

misc_deregister(&misc); //注銷設備

}

module_init(dev_init);

module_exit(dev_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("FriendlyARM Inc.");

MODULE_DESCRIPTION("S3C2410/S3C2440 PWM Driver");測設程序如下:

#include

#include

#include

#include

#define PWM_IOCTL_SET_FREQ 1

#define PWM_IOCTL_STOP 2

#define ESC_KEY 0x1b

static int getch(void)

{

struct termios oldt,newt;

int ch;

if (!isatty(STDIN_FILENO)) {

fprintf(stderr, "this problem should be run at a terminal\n");

exit(1);

}

// save terminal setting

if(tcgetattr(STDIN_FILENO, &oldt) < 0) {

perror("save the terminal setting");

exit(1);

}

// set terminal as need

newt = oldt;

newt.c_lflag &= ~( ICANON | ECHO );

if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) {

perror("set terminal");

exit(1);

}

ch = getchar();

// restore termial setting

if(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) {

perror("restore the termial setting");

exit(1);

}

return ch;

}

static int fd = -1;

static void close_buzzer(void);

static void open_buzzer(void)

{

fd = open("/dev/pwm", 0);

if (fd < 0) {

perror("open pwm_buzzer device");

exit(1);

}

// any function exit call will stop the buzzer

atexit(close_buzzer);

}

static void close_buzzer(void)

{

if (fd >= 0) {

ioctl(fd, PWM_IOCTL_STOP);

close(fd);

fd = -1;

}

}

static void set_buzzer_freq(int freq)

{

// this IOCTL command is the key to set frequency

int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, freq);

if(ret < 0) {

perror("set the frequency of the buzzer");

exit(1);

}

}

static void stop_buzzer(void)

{

int ret = ioctl(fd, PWM_IOCTL_STOP);

if(ret < 0) {

perror("stop the buzzer");

exit(1);

}

}

int main(int argc, char **argv)

{

int freq = 1000 ;

open_buzzer();

printf( "\nBUZZER TEST ( PWM Control )\n" );

printf( "Press +/- to increase/reduce the frequency of the BUZZER\n" ) ;

printf( "Press 'ESC' key to Exit this program\n\n" );

while( 1 )

{

int key;

set_buzzer_freq(freq);

printf( "\tFreq = %d\n", freq );

key = getch();

switch(key) {

case '+':

if( freq < 20000 )

freq += 10;

break;

case '-':

if( freq > 11 )

freq -= 10 ;

break;

case ESC_KEY:

case EOF:

stop_buzzer();

exit(0);

default:

break;

}

}

}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/541196.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/541196.shtml
英文地址,請注明出處:http://en.pswp.cn/news/541196.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2019聊大考研計算機調劑,2019年聊城大學碩士研究生預調劑工作說明

教育部2019年分數線與招生計劃尚未確定&#xff0c;根據往年分數線與報考情況&#xff0c;現將我校2019年碩士研究生預調劑工作說明如下&#xff1a;一、調劑要求:(一)只接受學歷為本科的考生調劑&#xff0c;應屆本科生優先;(二)初試成績達到報考專業與擬調劑專業教育部A區分數…

SylixOS磁盤高速傳輸

SylixOS管線模型分析前文主要介紹了SylixOS中的塊設備CACHE管理&#xff0c;本章主要介紹磁盤高速傳輸。在CAHCE回寫中SyilxOS采取了兩種方式&#xff0c;即直接回寫和多管線并發回寫。并發寫管線通過多線程并發處理CACHE提交的寫請求&#xff0c;實現磁盤高速傳輸。SylixOS中通…

kotlin int最大值_Kotlin程序查找三個數字中的最大值

kotlin int最大值Input 3 integer numbers, we have to find the largest of these input numbers. 輸入3個整數&#xff0c;我們必須找到這些輸入數字中最大的一個。 Example: 例&#xff1a; Input:First number: 10Second number: 20Third number: 30Output:Largest numbe…

計算機社團活動展望未來,社團展望未來寄語簡短,如何寫社團未來計劃

呵呵&#xff0c;你不會是社團的會長吧&#xff0c;不會寫這個的話說不過去了&#xff0c;而且沒有你想象的那么復雜&#xff0c;有條理&#xff0c;分類的寫下去就可以了&#xff0c;但這里不要太多的口水話&#xff01;再者你可以去問一下其他社團的負責人的&#xff01;&…

判斷五個分數等級劃分_壓力表精度等級怎么算?壓力表精度等級劃分及檢驗項目...

壓力表是一種典型的軸向精密壓力表&#xff0c;是用來測量介質壓力的儀表&#xff0c;在工業生產也是常用的儀表&#xff0c;對生產起到了非常重要的作用&#xff0c;壓力表的所顯示壓力的精度&#xff0c;就成了我們非常重要的一個參數。今天小編就來為大家說說壓力表精度等級…

stl make_heap_通過使用make_heap()創建堆| C ++ STL

stl make_heapWhat is Heap Data structure? 什么是堆數據結構&#xff1f; Heap is a tree-based which is used for fast retrieval of largest (max heap) or smallest (min heap) element. This DS is used in the priority queue, prims algo, heap sort and many more.…

cad安裝日志文件發生錯誤_蘋果電腦Mac os系統重裝時出現“準備安裝時發生錯誤”解決方案...

題外話&#xff1a;自己是個電腦小白&#xff0c;因為自己的MacBook Air 不那么流暢了&#xff0c;就按照其他知乎大佬們說的步驟進行重裝電腦。&#xff08;2017款 MacBook Air 以下就用Air代替&#xff09; 自己先把電腦重新啟動&#xff0c;按照步驟按住commandR&#xff0c…

mac mail 刪除郵件服務器,Mac郵件應用程序Mail設置

1、 點擊Mail。如果從未使用Mail 設置任何電子郵件賬戶&#xff0c;則出現“歡迎使用 Mail”頁&#xff1b;如果已使用Mail創建電子郵件賬戶&#xff0c;則在“郵件”菜單上單擊“首選項”&#xff0c;在“賬戶”選項卡上單擊導航窗格底部的加號 ()&#xff0c;打開“添加賬戶”…

sass使用相關報錯

1. 移動端一像素邊框的縮放&#xff0c;我創建了三個文件&#xff1a;mixin.scss &#xff0c; base.scss&#xff0c;index.scss 在index.scss里面引入全局樣式文件&#xff0c; 在base.scss文件中編寫 根據媒體查詢設置不同的縮放比例&#xff0c;報錯如下&#xff1a; media…

client netty 主動發數據_netty案例,netty4.1基礎入門篇十一《netty udp通信方式案例Demo》...

小傅哥 | https://bugstack.cn 沉淀、分享、成長&#xff0c;讓自己和他人都能有所收獲。專注于原創專題案例編寫&#xff0c;目前已完成的專題有&#xff1b;Netty4.x實戰專題案例、用Java實現JVM、基于JavaAgent的全鏈路監控、手寫RPC框架、架構設計專題案例、源碼分析等。你…

服務器硬件oid,HPE ProLiant DL580 Gen10 服務器

用可擴展 4U 外形提供可擴展性能HPE ProLiant DL580 Gen10 服務器支持多達四個英特爾至強鉑金和金牌處理器&#xff0c;與上一代英特爾 至強 可擴展處理器相比&#xff0c;每個內核的性能提升高達 11%[5]&#xff0c;可借助 4U 可擴展機箱&#xff0c;實現 4P 計算能力。多達 4…

php-對銀行卡號做掩碼處理

1.實現代碼如下/*** 對銀行卡號進行掩碼處理* param string $bankCardNo 銀行卡號* return string 掩碼后的銀行卡號*/function formatBankCardNo($bankCardNo){//截取銀行卡號前4位$prefix substr($bankCardNo,0,4);//截取銀行卡號后4位$suffix substr($bankCa…

最長遞增子序列 子串_最長遞增奇偶子序列

最長遞增子序列 子串Problem statement: 問題陳述&#xff1a; Given a sequence of numbers you have to find out the length of the longest increasing odd even subsequence and print the length of the subsequence. The sequence will be maintaining like, (odd ) -&…

echarts 柱狀圖不顯示y坐標軸_Python+matplotlib自定義坐標軸位置、顏色、箭頭

圖書推薦&#xff1a;《Python程序設計基礎與應用》(ISBN&#xff1a;9787111606178)&#xff0c;董付國&#xff0c;機械工業出版社圖書詳情&#xff1a;用書教師可以聯系董老師獲取教學大綱、課件、源碼、教案、考試系統等配套教學資源。使用Pythonnumpymatplotlib這樣的組合…

css3瀏覽,css3支持哪些瀏覽器?

CSS3 帶來眾多全新的設計體驗&#xff0c;但有一個問題值得考慮&#xff1a;瀏覽器對 CSS3 特性的兼容情況如何&#xff1f;因為頁面最終離不開用瀏覽器來渲染&#xff0c;并不是所有瀏覽器都完全支持 CSS3 的特性。有時花時間寫的效果只能在特定的瀏覽器下有效&#xff0c;這意…

print函數python_帶有結束參數的Python print()函數

print函數pythonprint()函數 (print() function) print() function is used to print message on the screen. print()函數用于在屏幕上打印消息。 Example: 例&#xff1a; # python print() function example# printing textprint("Hello world!")print("He…

python各位數字之和為5的數_『Python基礎-5』數字,運算,轉換

『Python基礎-5』數字,運算,轉換目錄基本的數字類型二進制,八進制,十六進制數字類型間的轉換數字運算1. 數字類型Python 數字數據類型用于存儲數學上的值&#xff0c;比如整數、浮點數、復數等。數字類型在python中是不可變類型&#xff0c;意思是一個變量被賦予了一個不一樣的…

移動游戲加載性能和內存管理全解析 學習

https://v.qq.com/iframe/player.html?vido0512etq2vm&tiny0&auto0 轉載于:https://www.cnblogs.com/revoid/p/7039232.html

css 軌道,html-當其他軌道增加時,CSS網格的軌道不會縮...

由于行和列定義中都包含1fr,因此水平和垂直空間受到限制-因此網格項目將平均共享它們.嘗試將其更改為自動用于行和列,您可以看到一切正常,但還不完美-請注意,懸停的網格項周圍存在空格&#xff1a;.grid--container {height: 100vh;width: 100vw;max-height: 100%;max-width: 1…

帶有示例的Python File readline()方法

文件readline()方法 (File readline() Method) readline() method is an inbuilt method in Python, it is used to get one line from the file, the method is called with this object (current file stream/IO object) and returns one line from the file, we can also sp…