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

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

1.2 打開XT2時(shí)鐘
在CCS(Code Composer Studio)中,多數(shù)情況需要用到內(nèi)部低頻晶振(LFXT1),然而現(xiàn)在我們沒用到它,而使用外部高頻晶振(XT2)。需要進(jìn)行如下配置:
(1)flash主程序分配區(qū)域
在 startup_ccs/hw_memmap.h 文件中添加如下宏定義:
#define HW_NMI (0xFFFEu)
將NMI vector定義設(shè)置在微控制器的外部RAM中。
(2)時(shí)鐘配置
在CPU主頻為16MHz(CLK)和數(shù)量級(jí)于4~20MHz的外部時(shí)鐘的設(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)時(shí)鐘,表示將此時(shí)鐘配置為使用XT2作為DCO FLL參考時(shí)鐘,UCSCTL4是時(shí)鐘門控寄存器,SELREF_2表示使用XT2作為DCO FLL參考時(shí)鐘,SELA_2表示設(shè)置ACLK時(shí)鐘源為XT2,SELS_4和SELM_4表示將時(shí)鐘源分別設(shè)置為CLK和MCLK。
1.3 實(shí)現(xiàn)方波讀寫操作
(1)打開輸出口
P8SEL |= BIT0;
這里P8SEL和SEL和dir是三個(gè)位于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端口在信號(hào)輸入時(shí),當(dāng)解析器的輸出跳變時(shí),端口會(huì)使用一個(gè)低頻率振蕩電路(低通濾波器)將輸入信號(hào)進(jìn)行濾波。濾波器按照設(shè)備的預(yù)定閾值設(shè)定為一個(gè)可濾波的更大上升沿時(shí)延(通常在幾微秒到幾百微秒之間),過濾掉了較慢的信號(hào)干擾。當(dāng)端口輸出時(shí),需要將端口濾波器關(guān)掉,否則會(huì)影響輸出。通過配置P8口的P8.0相應(yīng)的FSEL控制寄存器,可以實(shí)現(xiàn)關(guān)閉數(shù)字濾波器。
(3)實(shí)現(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兩個(gè)定時(shí)器,實(shí)現(xiàn)了單片機(jī)生成一段特定占空比的方波信號(hào)。這里的定時(shí)器是通用定時(shí)器(Timer_A),是單片機(jī)中常用的高級(jí)定時(shí)器。
TA0CCR0是計(jì)數(shù)器閾值,TA0CCR1是比較器閾值,TA0CCTL1是比較器控制器,OUTMOD_7表示設(shè)置輸出模式為“比較輸出模式7”(即:除計(jì)數(shù)器為0時(shí)置位外,其他情況下,比較器寄存器與計(jì)數(shù)器寄存器相等則翻轉(zhuǎn)信號(hào),否則不翻轉(zhuǎn))。TASSEL_2是選擇TA的時(shí)鐘源為XT2,MC_UPDOWN是計(jì)數(shù)模式設(shè)為向上向下計(jì)數(shù)模式,TACLR是允許清除TA計(jì)時(shí)器計(jì)數(shù)器。
1.4 完整代碼
下面是生成方波信號(hào)的完整代碼:
#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)用于馬達(dá)控制、LED的亮度控制等場(chǎng)合。下面我們將介紹在Linux系統(tǒng)中如何實(shí)現(xiàn)PWM技術(shù)。
2.1 硬件搭建
PWM技術(shù)的硬件搭建如圖2所示,需要一個(gè)單片機(jī)作為信號(hào)發(fā)生器和一個(gè)示波器進(jìn)行觀察。

2.2 驅(qū)動(dòng)器
PWM技術(shù)的es0風(fēng)驅(qū)動(dòng)器通過將電源轉(zhuǎn)換為PWM信號(hào)來控制電機(jī)的轉(zhuǎn)速。驅(qū)動(dòng)器是由一個(gè)控制器、一個(gè)驅(qū)動(dòng)芯片和一個(gè)三相橋組成的??刂破髫?fù)責(zé)控制電機(jī)的電流,驅(qū)動(dòng)芯片ON/OFF是在這個(gè)信號(hào)的控制下進(jìn)行的。使用PWM技術(shù),我們可以調(diào)整PWM信號(hào)的峰值來控制電機(jī)的輸出功率。
2.3 PWM方式實(shí)現(xiàn)
在Linux系統(tǒng)中,實(shí)現(xiàn)PWM方式有兩種:軟件PWM和硬件PWM。軟件PWM的優(yōu)點(diǎn)是實(shí)現(xiàn)簡(jiǎn)單,但精度有限,很難實(shí)現(xiàn)更高分辨率的PWM波形。硬件PWM技術(shù)通過直接控制MCU的輸出端口來生成高分辨率的PWM波形,但由于接口的限制,硬件PWM技術(shù)的靈活性比軟件PWM要低。
下面我們將介紹如何在Linux系統(tǒng)中通過硬件PWM技術(shù)來實(shí)現(xiàn)控制一個(gè)3相電機(jī)的轉(zhuǎn)速。
(1)配置PWM輸出輸出引腳
我們需要向設(shè)備樹引擎添加定時(shí)器、PWM驅(qū)動(dòng)程序和節(jié)點(diǎn),以實(shí)現(xiàn)PWM控制。
給xilinx,dma節(jié)點(diǎn)添加定時(shí)器屬性,將PWM信號(hào)輸出到zynq (ps)端口。定時(shí)器只需要設(shè)定時(shí)鐘源和計(jì)數(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è)備文件,以控制電機(jī)的速度。
(2)控制電機(jī)的速度
控制電機(jī)的轉(zhuǎn)速是通過調(diào)整PWM信號(hào)的頻率和占空比來實(shí)現(xiàn)的。具體來說,我們可以通過增加PWM信號(hào)的頻率來加快電機(jī)的轉(zhuǎn)速,同時(shí)通過增加PWM信號(hào)的占空比來提高其輸出功率。
下面是代碼,用于通過PWM技術(shù)驅(qū)動(dòng)一個(gè)3相電機(jī):
/* 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)驗(yàn)豐富以策略為先導(dǎo)10多年以來專注數(shù)字化網(wǎng)站建設(shè),提供企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計(jì),響應(yīng)式網(wǎng)站制作,設(shè)計(jì)師量身打造品牌風(fēng)格,熱線:028-86922220小車的電機(jī)驅(qū)動(dòng)要不要L298N?我是想用PMW方式調(diào)速,是單片機(jī)直接輸出高低電平到L298N嗎?
我驅(qū)動(dòng)電機(jī)的時(shí)候用了光耦,不用的話電機(jī)停不下來,電路圖百度文庫有,找不到的話我給你發(fā)一個(gè)。
不需要用L298N,將上圖的DC MTR1接到你單片機(jī)的PWM1口,DC MTR2接到單族鏈片機(jī)的PWM2口,你需要程序做的是:清DC MTR2為低電平,并輸出PWM信號(hào)到PWM1口;反之亦然。
注意:該電路不帶過流檢測(cè),單片機(jī)塵穗賣復(fù)位的時(shí)候一定要清PWM1、PWM2兩個(gè)端口,否則程序如一直不啟動(dòng),兩個(gè)口均為高電平狀態(tài),此時(shí)Q1、Q2、Q4、Q6四個(gè)三極派逗管為導(dǎo)通狀態(tài)!
達(dá)林頓管有壓降,不可避免的對(duì)電機(jī)速度有限制,可以試著用場(chǎng)春棚做效應(yīng)管,場(chǎng)效應(yīng)管沒有壓降,但是驅(qū)動(dòng)電壓高,可以先升壓再和告用單片機(jī)控制三極扒衡管,進(jìn)而控制場(chǎng)效應(yīng)管,這樣就把速度提上去了!
L298N的內(nèi)部結(jié)構(gòu)就是你圖里的橋接??梢圆挥娩h薯L298N。
可以不用光耦。
PWM(不是PMW)可以直接接298上的兩個(gè)使能擾和端。
我用298做了個(gè),也是PWM調(diào)銀李者速,控制兩個(gè)電機(jī)。沒有用光耦。
基于單片機(jī)信號(hào)發(fā)生器設(shè)計(jì)重點(diǎn)研究問題是什么
利用單片機(jī)做信號(hào)發(fā)生器,其重點(diǎn)就是單片機(jī)的主頻啦
因?yàn)橹黝l代表著程序運(yùn)行的時(shí)間,這個(gè)時(shí)間是完成一次程序的從頭到尾單片機(jī)內(nèi)部所需的時(shí)間,而運(yùn)行一次只能輸出一種端口狀態(tài),那么需要方波輸出,則需要單片機(jī)運(yùn)行兩次才能真正輸出一個(gè)方波信號(hào),所以主頻才是升毀重中之重。
另外還有程序的整體步數(shù),就是程序的長(zhǎng)度或多少,程序語句越多,運(yùn)行速度也越慢,輸出的信號(hào)頻率也越低
例神宴如想做一個(gè)1MHz的方波發(fā)生器,那么51單片機(jī)的更高主頻是12MHz,然而真正輸出的更高只能達(dá)到12分之一,那就是1MHz,勉勉強(qiáng)強(qiáng)算是可以
如果超過1MHz的波形,51類單片機(jī)是達(dá)不到效果了,只能選擇其它單片機(jī)
下面是本人曾經(jīng)利用單吵瞎備片機(jī)做的PMW信號(hào)發(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;//定時(shí)器初始化
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 //定時(shí)器 0 中斷
{
TH0=0xff; s++;
if(s>=h){ TR0=0; TR1=1; D=0; s=0; }//開始時(shí)間
}
/***************************************************************************
/void int1() interrupt 3 //定時(shí)器 1 中斷
{
TH1=0xff; s++;
if(s>=m){ TR1=0; TR0=1; D=1; s=0; }//休止時(shí)間
}
/***************************************************************************/
基于單片機(jī)信號(hào)發(fā)生器設(shè)計(jì)
讓我來幫你 .
關(guān)于linux 方波輸出pmw的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都網(wǎng)站建設(shè)選創(chuàng)新互聯(lián)(?:028-86922220),專業(yè)從事成都網(wǎng)站制作設(shè)計(jì),高端小程序APP定制開發(fā),成都網(wǎng)絡(luò)營(yíng)銷推廣等一站式服務(wù)。
文章題目:Linux實(shí)現(xiàn)方波輸出和PWM技術(shù)(linux方波輸出pmw)
網(wǎng)址分享:http://fisionsoft.com.cn/article/djdcpeg.html


咨詢
建站咨詢
