新聞中心
隨著人們對數(shù)字化和自動化需求的增加,嵌入式系統(tǒng)在市場上的應(yīng)用越來越廣泛,而Linux系統(tǒng)作為軟件開發(fā)非常成熟的一個操作系統(tǒng),被廣泛應(yīng)用于嵌入式系統(tǒng)中。在嵌入式系統(tǒng)開發(fā)中,有許多應(yīng)用需要使用到PWM技術(shù)或者方波輸出,本文將會詳細講解如何在Linux系統(tǒng)中實現(xiàn)方波輸出和PWM技術(shù)。

一、方波輸出
方波信號是一種具有特定周期和占空比的信號,一般用于嵌入式系統(tǒng)中的定時器、DAC轉(zhuǎn)換、蜂鳴器等場合,現(xiàn)在我們將借助Linux系統(tǒng)實現(xiàn)方波輸出。
1.1 硬件搭建
方波輸出的硬件搭建如圖1所示,需要一個單片機作為信號發(fā)生器和一個示波器進行觀察。

1.2 打開XT2時鐘
在CCS(Code Composer Studio)中,多數(shù)情況需要用到內(nèi)部低頻晶振(LFXT1),然而現(xiàn)在我們沒用到它,而使用外部高頻晶振(XT2)。需要進行如下配置:
(1)flash主程序分配區(qū)域
在 startup_ccs/hw_memmap.h 文件中添加如下宏定義:
#define HW_NMI (0xFFFEu)
將NMI vector定義設(shè)置在微控制器的外部RAM中。
(2)時鐘配置
在CPU主頻為16MHz(CLK)和數(shù)量級于4~20MHz的外部時鐘的設(shè)定下,格式為:
#include
…
UCSCTL3 |= SELREF_2; // Set DCO FLL reference = XT2 = 16MHz
UCSCTL4 |= SELA_2; // Set ACLK = XT2 = 16MHz
UCSCTL0 |= UCSON; // Enable UCS subsystem
UCSCTL4 |= SELS_4 | SELM_4; // CLK=MCLK=XT2
此處,UCSCTL3是內(nèi)部系統(tǒng)時鐘,表示將此時鐘配置為使用XT2作為DCO FLL參考時鐘,UCSCTL4是時鐘門控寄存器,SELREF_2表示使用XT2作為DCO FLL參考時鐘,SELA_2表示設(shè)置ACLK時鐘源為XT2,SELS_4和SELM_4表示將時鐘源分別設(shè)置為CLK和MCLK。
1.3 實現(xiàn)方波讀寫操作
(1)打開輸出口
P8SEL |= BIT0;
這里P8SEL和SEL和dir是三個位于io.h頭文件中的宏定義。P8SEL代表P8口,SEL口和DIR口分別用于配置端口是輸入還是輸出,這里我們將P8口的P8.0位于SEL高阻態(tài)。
(2)關(guān)閉濾波器
/*
* Regarding Digital IOs’ filtering, if a I/O line,
* primary or secondary function, is expected to experience
* a sharp rising or falling edge, and that we want to
* capture that signal, one would have to disable the
* digital filter associated to the I/O line using the
* digital IO disable register DIO#_FSEL.
*
* DIO#_FSEL &= ~bitfield;
*
* DIO# is the name of the Digital IO and bitfield is the
* bitfield associated to that Digital IO.
* __even_in_range is a macro that dynamically compares the
* user defined number with the base of the register.
*
* We’ll disable all digital filters for this example.
*/
P8DIR |= BIT0;
P8DS |= BIT0;
P8OUT &= ~BIT0;
P8SEL &= ~BIT0;
P8REN &= ~BIT0;
P8SEL |= BIT0;
這里需要將濾波器概念介紹一下。數(shù)字IO端口在信號輸入時,當(dāng)解析器的輸出跳變時,端口會使用一個低頻率振蕩電路(低通濾波器)將輸入信號進行濾波。濾波器按照設(shè)備的預(yù)定閾值設(shè)定為一個可濾波的更大上升沿時延(通常在幾微秒到幾百微秒之間),過濾掉了較慢的信號干擾。當(dāng)端口輸出時,需要將端口濾波器關(guān)掉,否則會影響輸出。通過配置P8口的P8.0相應(yīng)的FSEL控制寄存器,可以實現(xiàn)關(guān)閉數(shù)字濾波器。
(3)實現(xiàn)方波輸出
while (1) { // Loop forever
period = 20; // 20ms period
pulsewidth = period / 2; // Time the signal stays high
TA0CCR0 = TA1CCR0 = period * 1000 / 25; // Counter for up/down mode
TA0CCR1 = TA1CCR1 = pulsewidth * 1000 / 25; // Time when output is high
TA0CCTL1 = TA1CCTL1 = OUTMOD_7; // Set output mode to toggle
TA0CTL = TA1CTL = TASSEL__XT2 | MC__UPDOWN | TACLR; // Set upcounter & clear timer
while (1){}; // Let period edge interrupt handle next pulse
}
在這段代碼中,我們通過配置TA0和TA1兩個定時器,實現(xiàn)了單片機生成一段特定占空比的方波信號。這里的定時器是通用定時器(Timer_A),是單片機中常用的高級定時器。
TA0CCR0是計數(shù)器閾值,TA0CCR1是比較器閾值,TA0CCTL1是比較器控制器,OUTMOD_7表示設(shè)置輸出模式為“比較輸出模式7”(即:除計數(shù)器為0時置位外,其他情況下,比較器寄存器與計數(shù)器寄存器相等則翻轉(zhuǎn)信號,否則不翻轉(zhuǎn))。TASSEL_2是選擇TA的時鐘源為XT2,MC_UPDOWN是計數(shù)模式設(shè)為向上向下計數(shù)模式,TACLR是允許清除TA計時器計數(shù)器。
1.4 完整代碼
下面是生成方波信號的完整代碼:
#include
…
int mn (void) {
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P8SEL |= BIT0; // Set P8.0 for secondary peripheral module function (GPIO output)
P8DIR |= BIT0; // Configure P8.0 as output
P8DS |= BIT0; // Connect P8.0 to I/O pad
P8OUT &= ~BIT0; // Set initial output to 0
P8SEL &= ~BIT0; // Disconnect P8.0 from NMI/nRST
P8REN &= ~BIT0; // Disable internal pullup resistor
P8SEL |= BIT0; // Select peripheral module function (in this case, TACLK)
while (1) { // Loop forever
period = 20; // 20ms period
pulsewidth = period / 2; // Time the signal stays high
TA0CCR0 = TA1CCR0 = period * 1000 / 25; // Counter for up/down mode
TA0CCR1 = TA1CCR1 = pulsewidth * 1000 / 25; // Time when output is high
TA0CCTL1 = TA1CCTL1 = OUTMOD_7; // Set output mode to toggle
TA0CTL = TA1CTL = TASSEL__XT2 | MC__UPDOWN | TACLR; // Set upcounter & clear timer
while (1){}; // Let period edge interrupt handle next pulse
}
…
二、PWM技術(shù)
PWM技術(shù)(Pulse-width modulation)又稱脈寬調(diào)制技術(shù),是一種通過調(diào)節(jié)周期相等的脈沖寬度來控制輸出電壓或電流的技術(shù),一般應(yīng)用于馬達控制、LED的亮度控制等場合。下面我們將介紹在Linux系統(tǒng)中如何實現(xiàn)PWM技術(shù)。
2.1 硬件搭建
PWM技術(shù)的硬件搭建如圖2所示,需要一個單片機作為信號發(fā)生器和一個示波器進行觀察。

2.2 驅(qū)動器
PWM技術(shù)的es0風(fēng)驅(qū)動器通過將電源轉(zhuǎn)換為PWM信號來控制電機的轉(zhuǎn)速。驅(qū)動器是由一個控制器、一個驅(qū)動芯片和一個三相橋組成的??刂破髫撠?zé)控制電機的電流,驅(qū)動芯片ON/OFF是在這個信號的控制下進行的。使用PWM技術(shù),我們可以調(diào)整PWM信號的峰值來控制電機的輸出功率。
2.3 PWM方式實現(xiàn)
在Linux系統(tǒng)中,實現(xiàn)PWM方式有兩種:軟件PWM和硬件PWM。軟件PWM的優(yōu)點是實現(xiàn)簡單,但精度有限,很難實現(xiàn)更高分辨率的PWM波形。硬件PWM技術(shù)通過直接控制MCU的輸出端口來生成高分辨率的PWM波形,但由于接口的限制,硬件PWM技術(shù)的靈活性比軟件PWM要低。
下面我們將介紹如何在Linux系統(tǒng)中通過硬件PWM技術(shù)來實現(xiàn)控制一個3相電機的轉(zhuǎn)速。
(1)配置PWM輸出輸出引腳
我們需要向設(shè)備樹引擎添加定時器、PWM驅(qū)動程序和節(jié)點,以實現(xiàn)PWM控制。
給xilinx,dma節(jié)點添加定時器屬性,將PWM信號輸出到zynq (ps)端口。定時器只需要設(shè)定時鐘源和計數(shù)器周期即可。
pwm-leds {
compatible = “pwm-leds”;
led0 {
pwms = ;
pwn-period = ;
line-names = “pwm0”;
default-brightness-level = ;
};
};
&pwm0 {
status = “okay”;
pwn-period = ; /* 100Hz with internal clock */
ti,shoot-yes;
};
配置完畢后,我們可以讀取PWM周期和占空比并將其寫入設(shè)備文件,以控制電機的速度。
(2)控制電機的速度
控制電機的轉(zhuǎn)速是通過調(diào)整PWM信號的頻率和占空比來實現(xiàn)的。具體來說,我們可以通過增加PWM信號的頻率來加快電機的轉(zhuǎn)速,同時通過增加PWM信號的占空比來提高其輸出功率。
下面是代碼,用于通過PWM技術(shù)驅(qū)動一個3相電機:
/* pwm_leds.c */
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME “pwm-leds”
static struct pwm_device *pwm_dev;
static struct device *dev;
static void pwm_leds_set_brightness_level(unsigned int level)
{
printk(KERN_INFO “pwm_leds: Set brightness level to %u\n”, level);
/* Level should be in the range of [0, pwn-period] */
level = min_t(unsigned int, pwm_get_period(pwm_dev), level);
/* Set PWM duty cycle */
pwm_config(pwm_dev, level, pwm_get_period(pwm_dev));
/* Enable the PWM signal */
pwm_enable(pwm_dev);
/* Wt a short while for the new settings to take effect */
msleep(50);
}
/* Device attribute callbacks */
static ssize_t brightness_level_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, “%u\n”,
pwm_get_duty_cycle(pwm_dev));
}
static ssize_t brightness_level_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
int value;
int ret;
ret = kstrtoint(buf, 10, &value);
if (ret
return ret;
if ((value pwm_get_period(pwm_dev)))
return -EINVAL;
pwm_leds_set_brightness_level(value);
return count;
}
/* Device attributes */
static DEVICE_ATTR(brightness_level, S_IWUSR|S_IRUGO,
brightness_level_show, brightness_level_store);
/* Platform device driver */
static int pwm_leds_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int err;
if (!np)
return -ENODEV;
pwm_dev = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(pwm_dev))
return PTR_ERR(pwm_dev);
/* Initialize device attributes */
err = device_create_file(&pdev->dev, &dev_attr_brightness_level);
if (err)
goto fl;
/* Create a new device node */
dev = device_create(pc_class, NULL, 0, NULL, DEVICE_NAME);
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
goto fl;
}
dev_set_drvdata(dev, pwm_dev);
return 0;
fl:
if (&dev_attr_brightness_level.attr)
device_remove_file(&pdev->dev, &dev_attr_brightness_level);
return err;
}
static int pwm_leds_remove(struct platform_device *pdev)
{
device_remove_file(&pdev->dev, &dev_attr_brightness_level);
device_unregister(dev);
return 0;
}
static struct platform_driver pwm_leds_driver = {
.probe = pwm_leds_probe,
.remove = pwm_leds_remove,
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
};
static int __init pwm_leds_init(void)
{
return platform_driver_register(&pwm_leds_driver);
}
static void __exit pwm_leds_exit(void)
{
platform_driver_unregister(&pwm_leds_driver);
}
MODULE_LICENSE(“GPL”);
module_init(pwm_leds_init);
module_exit(pwm_leds_exit);
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián),建站經(jīng)驗豐富以策略為先導(dǎo)10多年以來專注數(shù)字化網(wǎng)站建設(shè),提供企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計,響應(yīng)式網(wǎng)站制作,設(shè)計師量身打造品牌風(fēng)格,熱線:028-86922220小車的電機驅(qū)動要不要L298N?我是想用PMW方式調(diào)速,是單片機直接輸出高低電平到L298N嗎?
我驅(qū)動電機的時候用了光耦,不用的話電機停不下來,電路圖百度文庫有,找不到的話我給你發(fā)一個。
不需要用L298N,將上圖的DC MTR1接到你單片機的PWM1口,DC MTR2接到單族鏈片機的PWM2口,你需要程序做的是:清DC MTR2為低電平,并輸出PWM信號到PWM1口;反之亦然。
注意:該電路不帶過流檢測,單片機塵穗賣復(fù)位的時候一定要清PWM1、PWM2兩個端口,否則程序如一直不啟動,兩個口均為高電平狀態(tài),此時Q1、Q2、Q4、Q6四個三極派逗管為導(dǎo)通狀態(tài)!
達林頓管有壓降,不可避免的對電機速度有限制,可以試著用場春棚做效應(yīng)管,場效應(yīng)管沒有壓降,但是驅(qū)動電壓高,可以先升壓再和告用單片機控制三極扒衡管,進而控制場效應(yīng)管,這樣就把速度提上去了!
L298N的內(nèi)部結(jié)構(gòu)就是你圖里的橋接??梢圆挥娩h薯L298N。
可以不用光耦。
PWM(不是PMW)可以直接接298上的兩個使能擾和端。
我用298做了個,也是PWM調(diào)銀李者速,控制兩個電機。沒有用光耦。
基于單片機信號發(fā)生器設(shè)計重點研究問題是什么
利用單片機做信號發(fā)生器,其重點就是單片機的主頻啦
因為主頻代表著程序運行的時間,這個時間是完成一次程序的從頭到尾單片機內(nèi)部所需的時間,而運行一次只能輸出一種端口狀態(tài),那么需要方波輸出,則需要單片機運行兩次才能真正輸出一個方波信號,所以主頻才是升毀重中之重。
另外還有程序的整體步數(shù),就是程序的長度或多少,程序語句越多,運行速度也越慢,輸出的信號頻率也越低
例神宴如想做一個1MHz的方波發(fā)生器,那么51單片機的更高主頻是12MHz,然而真正輸出的更高只能達到12分之一,那就是1MHz,勉勉強強算是可以
如果超過1MHz的波形,51類單片機是達不到效果了,只能選擇其它單片機
下面是本人曾經(jīng)利用單吵瞎備片機做的PMW信號發(fā)生器程序,僅供參考
/***************************************************************************/
#include//頻率約為 2.37 KHz
//根據(jù)按鍵來控制輸出波形
it D=P2^0 ; //端口定義
int h,m,s,f;
/***************************************************************************/
void main(void)
{
TMOD=0x22; EA=1; ET0=1; ET1=1; TR0=1;//定時器初始化
while(1)
{
switch(P0)
{
case 0xfe : h=1; break;
case 0xfd : h=2; break;
case 0xfb : h=3; break;
case 0xf7 : h=4; break;
case 0xef : h=5; break;
case 0xdf : h=6; break;
case 0xbf : h=7; break;
case 0x7f : h=8; break;
default : h=9; break;
}
m=10-h;
}
}
/***************************************************************************/
void int0() interrupt 1 //定時器 0 中斷
{
TH0=0xff; s++;
if(s>=h){ TR0=0; TR1=1; D=0; s=0; }//開始時間
}
/***************************************************************************
/void int1() interrupt 3 //定時器 1 中斷
{
TH1=0xff; s++;
if(s>=m){ TR1=0; TR0=1; D=1; s=0; }//休止時間
}
/***************************************************************************/
基于單片機信號發(fā)生器設(shè)計
讓我來幫你 .
關(guān)于linux 方波輸出pmw的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都網(wǎng)站建設(shè)選創(chuàng)新互聯(lián)(?:028-86922220),專業(yè)從事成都網(wǎng)站制作設(shè)計,高端小程序APP定制開發(fā),成都網(wǎng)絡(luò)營銷推廣等一站式服務(wù)。
新聞標(biāo)題:Linux實現(xiàn)方波輸出和PWM技術(shù)(linux方波輸出pmw)
當(dāng)前地址:http://www.dlmjj.cn/article/djdcpeg.html


咨詢
建站咨詢
