ขอถามกูรูทั้งหลายหน่อยครับ
ผมมีความจำเป็นต้องใช้ PWM 3 channels.
ไปเปิดดู ใน atmega 48 (ถูกตังหน่อย ว่าจะใช้ attiny 44/45 มีไม่พอให้ใช้ ) พบว่า มี pwm ให้ใช้ 6 channels
จะใช้ Fast PWM mode
ไปที่ Timer/counter0 มันให้ใช้
ที่ COM0A0/A1 ได้ 1 channel
ที่ COM0B0/B1 ได้อีก 1 channel
สงสัยว่า ผมจะใช้พร้อมกันได้หรือเปล่าครับ ยังไม่เคยลอง
ก่อนจะลุยเอง...... อยากจะถามผู้ที่เคยเล่นก่อนว่า
"ใช้พร้อมกันได้หรือเปล่า" โดยอาศัยจาก Timer/counter เดียวกัน
( ในที่นี้คือ Timer/Counter0 โดยจะเปิดใช้ com0a & com0b พร้อมกัน และใช้ pwm ค่าต่างกัน )
เคยเล่นแต่ ช่องเดียว ไม่เคยใช้ ทีละมากกว่า หนึ่งช่อง
หากได้ เหลืออีก channel คงต้องไปเอามาจาก Timer/Counter2 8 bits เช่นกัน
ขอบคุณสำหรับคำแนะนำ/ชี้แนะ
ได้ครับครับ แต่ความถี่ต้องเหมือนกัน duty แต่ละ Chanel ปรบเปลี่ยนอิสระโดย OCxA, OCxB, OCxC
ถ้าใช้ attiny 45 สามารถใช้ Software PWM ได้ครับ ได้ถึง 6 Channel
ลองดู Application Note (AVR136) ของ ATMEL นะครับ มีตัวอย่าง Code ด้วย
ฉันเอา Timer0 มานับค่ะ ตั้งแต่ 0-255 เสร็จแล้วในรูทีน Timer ฉันเอา Array ของแต่ละขามารับเอา
สมมติจะเอาออกที่พอร์ต B จำนวน 8 Channel ก็ทำได้ (แต่ต้องที่ความถี่เดียวกัน)
ตัวอย่างเช่น อยากให้พอร์ต B0 ถึง B7 เป็น PW(0) ถึง PW(7) แล้วเอาสัญญาณออกช่องนี้ด้วยความถี่เดียวกัน แต่ duty ต่างกัน ทำแบบนี้นะคะ
Dim Pw(7) as Byte
Dim Tik as Byte
Config Timer0 = Timer, Prescale=8 '<<<< ตรงนี้เปลี่ยนความถี่ได้ค่ะ
Enable Interrupts
Enable Timer0
On Timer0 Pwms
Start Timer0
Pw(0)=1 'กำหนด Duty cycle ของแต่ละ Channel ตรงนี้นะคะ
Pw(1)=7 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(2)=15 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(3)=31 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(4)=63 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(5)=127 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(6)=255 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(7)=0 'กำหนด Duty cycle ตรงนี้นะคะ
Pwms:
Incr Tik
If Tik = 255 Then
Tik = 0
Portb = 0
End If
If Tik > Pw(7) Then PortB.7 = 1
If Tik > Pw(6) Then PortB.6 = 1
If Tik > Pw(5) Then PortB.5 = 1
If Tik > Pw(4) Then PortB.4 = 1
If Tik > Pw(3) Then PortB.3 = 1
If Tik > Pw(2) Then PortB.2 = 1
If Tik > Pw(1) Then PortB.1 = 1
If Tik > Pw(0) Then PortB.0 = 1
Return
แบบนี้จะได้ PWM ตั้ง 8 ช่องที่ความถี่เดียวกัน แต่ Duty ไม่ซ้ำกันเลย
(http://cmu.mine.nu/teach/avr/pwm/pwm.JPG)
ส่วนนี่ Code + HEX + Proteus DSN ค่ะ
http://cmu.mine.nu/teach/avr/pwm (http://cmu.mine.nu/teach/avr/pwm)
ในความเห็นผม
ถ้าความถี่สูงๆหน่อย ใช้ Hardware ที่เป็น PWM จะดีกว่าครับ (ไม่กินแรง CPU เลย เพราะให้่ Hardware ทำงานไปอย่าง อิสระ อาจต้อง Syncronize บ้างตอนเปลี่ยนค่า)
แต่ถ้าความถี่ไม่สูงนัก ใช้ Software อย่างที่ท่าน Crywolf ได้แนะนำไว้ก็ได้ครับ จะกินแรง CPU นิดหน่อย เพราะต้อง interrupt cpu เป็นระยะ แต่ได้ช่องมากแน่นอน
http://www.atmel.com/Images/doc8020.pdf
http://howaboutanorange.com/avrpwm
http://jeelabs.org/2010/10/03/software-pwm-at-1-khz
อันนี้ เขาคุยกันเรื่อง PWM HW/SW
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=107185&start=0
Quote from: samira on February 19, 2013, 03:15:48 AM
ขอถามกูรูทั้งหลายหน่อยครับ
ผมมีความจำเป็นต้องใช้ PWM 3 channels.
ไปเปิดดู ใน atmega 48 (ถูกตังหน่อย ว่าจะใช้ attiny 44/45 มีไม่พอให้ใช้ ) พบว่า มี pwm ให้ใช้ 6 channels
จะใช้ Fast PWM mode
ไปที่ Timer/counter0 มันให้ใช้
ที่ COM0A0/A1 ได้ 1 channel
ที่ COM0B0/B1 ได้อีก 1 channel
สงสัยว่า ผมจะใช้พร้อมกันได้หรือเปล่าครับ ยังไม่เคยลอง
ก่อนจะลุยเอง...... อยากจะถามผู้ที่เคยเล่นก่อนว่า
"ใช้พร้อมกันได้หรือเปล่า" โดยอาศัยจาก Timer/counter เดียวกัน
( ในที่นี้คือ Timer/Counter0 โดยจะเปิดใช้ com0a & com0b พร้อมกัน และใช้ pwm ค่าต่างกัน )
เคยเล่นแต่ ช่องเดียว ไม่เคยใช้ ทีละมากกว่า หนึ่งช่อง
หากได้ เหลืออีก channel คงต้องไปเอามาจาก Timer/Counter2 8 bits เช่นกัน
ขอบคุณสำหรับคำแนะนำ/ชี้แนะ
ขอตอบ สำหรับ atmega48 นะครับ
Q: "ใช้พร้อมกันได้หรือเปล่า" โดยอาศัยจาก Timer/counter เดียวกัน
( ในที่นี้คือ Timer/Counter0 โดยจะเปิดใช้ com0a & com0b พร้อมกัน และใช้ pwm ค่าต่างกัน )
เคยเล่นแต่ ช่องเดียว ไม่เคยใช้ ทีละมากกว่า หนึ่งช่องA: ใช้พร้อมกันได้ครับ ตั้งที่ OCR0A และ OCR0B ของ Timer 0 ได้เลย
Q: หากได้ เหลืออีก channel คงต้องไปเอามาจาก Timer/Counter2 8 bits เช่นกันA : ใช้ที่ Timer 2 ก็ได้ครับ ตั้งที่ OCR2A และ OCR2B เป็็นของ Timer 2 ครับ
ขอขอบคุณทุกท่านที่มาชี้แนะ และ อธิบายครับ
คิดว่าคงจะใช้ ความถี่เดียวกันครับ
ผมต้องการเอาไปคุม พัดลม ( เล็กๆ ) 3 ตัว ด้วยความเร็วไม่เท่ากัน
ส่วน channel 3 คงต้องไปเอามาจาก timer/counter2
ครับ attiny45 ใช้ได้ ผมดูผิด อ่านเร็วไปเอง ขอบคุณมากครับ ท่าน crywolf
คงต้องศึกษาตัวอย่างที่ อ. Jmew เอามาแสดง น่าสนใจ ขอบคุณครับ
ต่อไปนี้ ก็ลุย................................
Soft PWM ทำได้ครับหาก load CPU ไม่เยอะมาก avr atmega ไม่มี multiple interrupt โดย hardware
HW PWM ใช้พร้อมกันได้ แต่จะต้องใช้ที่ความถี่เดี่ยวกันใน timer เดียวกัน แต่หากเป็น timer คนละตัวก็ใช้คนละความถี่ได้ครับ
ส่วน Soft pwm นั้น หากความถี่ไม่สูงสามารถใช้ได้ดีครับ อย่างการขับ rc-servo ผมก็ยังใช้ soft pwm เนื่องจาก ใช้ความถี่ต่ำ mega48 เอามาขับ rc-servo 20 ช่อง ยังไหวครับ
soft PWM ( AVR 136) เท่าที่ไปอ่านดู หากผมเข้าใจไม่ผิด
ที่ clk = 8 MHz จะได้ frequency ราว 8MHz / 256/256 ≈ 122 Hz แค่นั้นเอง
อยากจะได้ frequency ~ 4K-8K ครับ ( ที่จริงก็ไม่จำเป็นว่าต้องใช้เร็วขนาดนี้ แต่อยากทำตามที่โครงการเขาแนะนำมา)
หากผมเข้าใจผิด กรุณาช่วยชี้แจงด้วยครับ
ขอบคุณมากที่กรุณาเข้ามาชี้แจง
ถ้าเอา 8 ระดับ จะได้ความถี่ประมาณ 4 kHz ค่ะ แต่ถ้าจะเอา 16 ระดับ ก็จะได้ประมาณ 2 kHz ยิ่งระดับมากขึ้น soft loop ก็จะมากขึ้นค่ะ คุณ samira ต้องการกี่ระดับคะ?
(http://image.ohozaa.com/i/g1d/n33nL7.PNG)
Quote from: JMew on February 23, 2013, 03:02:47 AM
ถ้าเอา 8 ระดับ จะได้ความถี่ประมาณ 4 kHz ค่ะ แต่ถ้าจะเอา 16 ระดับ ก็จะได้ประมาณ 2 kHz ยิ่งระดับมากขึ้น soft loop ก็จะมากขึ้นค่ะ คุณ samira ต้องการกี่ระดับคะ?
ไม่แน่ใจว่าเข้าใจคำว่า "ระดับ" ของ อ Jmew ถูกต้องหรือเปล่า ผมจะเดาว่า อ หมายถึง 8 channels ใช่หรือเปล่า
หากใช่ คิดว่า แค่ 4K ผมก็คงจะเอาไปใช้ได้ครับ
ที่จะทำ คือ จะใช้ Potentiometer( POT) เป็นตัวกำกับความเร็วของแต่ละช่อง กล่าวคือ จะเอาค่าของมัน ( ADC ) ไปใช้เป็นตัวปรับ กำหนดค่า duty cycle ครับ
อยากถาม อ Jmew ว่า วิธีของ อ นั้น คำนวน frequency ได้อย่างไร ??
ขอบคุณครับ
ตรง code นี้ค่ะ
Dim Pw(7) as Byte
Dim Tik as Byte
Config Timer0 = Timer, Prescale=1 '<<<< ตรงนี้เปลี่ยนความถี่ได้ค่ะ
Enable Interrupts
Enable Timer0
On Timer0 Pwms
Start Timer0
Pw(0)=1 'กำหนด Duty cycle ของแต่ละ Channel ตรงนี้นะคะ
Pw(1)=7 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(2)=15 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(3)=31 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(4)=63 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(5)=127 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(6)=255 'กำหนด Duty cycle ตรงนี้นะคะ
Pw(7)=0 'กำหนด Duty cycle ตรงนี้นะคะ
Pwms:
Incr Tik
If Tik = 255 Then < ระดับอยู่ตรงนี้ ตั้งแต่ 0 ถึง 255 มี 256 ระดับ เราเปลี่ยนตรงนี้ได้นะคะ
Tik = 0
Portb = 0
End If
If Tik > Pw(7) Then PortB.7 = 1
If Tik > Pw(6) Then PortB.6 = 1
If Tik > Pw(5) Then PortB.5 = 1
If Tik > Pw(4) Then PortB.4 = 1
If Tik > Pw(3) Then PortB.3 = 1
If Tik > Pw(2) Then PortB.2 = 1
If Tik > Pw(1) Then PortB.1 = 1
If Tik > Pw(0) Then PortB.0 = 1
Return
ที่ prescale = 1 นะคะ Timer0 จะ overflow ทุก ๆ 0.000032 วินาที และจะนับ Tik ขึ้นทีละ 1 จนถึง 255
ทำให้ความถี่ลดลง เหลือ ประมาณ 8000000/256/256 = 122.07 Hz
แต่ถ้าเราเปลี่ยนให้ Tik นับแค่ 8 ระดับ ความถี่ที่ได้ก็จะเป็น 8000000/256/8 = 3906.25 Hz
แต่ถ้าเปลี่ยนให้ Tik นับ 16 ระดับ ความที่ที่ได้ก็จะเป็น 8000000/256/16 = 1953.125 Hz ค่ะ
มีอีกวิธีหนึ่ง คือใช้ Timer1 แล้ว Match Compare ค่ะ
คือทำแบบนี้
Config Timer1 = Timer , Prescale = 1 , Clear Timer = 1
On Compare1a Pwms
Enable Oc1a
Compare1a = 80 ' จะเกิด interrupt ทุก ๆ 10 us ถ้าใช้ clock 8 MHz คราวนี้เราก็กำหนดเวลาตรงนี้ค่ะ
Enable Interrupts
PWM 3CH ความถี่ประมาณ 4KHz บน ATtiny45 ใช้ Timer 2 ตัว
uint8_t r=0, g=85, b=170;
DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;
TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
TCCR0B = 0<<WGM02 | 3<<CS00;
TCCR1 = 0<<PWM1A | 0<<COM1A0 | 7<<CS10;
GTCCR = 1<<PWM1B | 2<<COM1B0;
OCR1C = 255;
for (;;)
{
OCR0A = r++;
OCR0B = g++;
OCR1B = b++;
_delay_ms(10);
}
Quote from: crywolf on February 23, 2013, 03:14:25 PM
PWM 3CH ความถี่ประมาณ 4KHz บน ATtiny45 ใช้ Timer 2 ตัว
uint8_t r=0, g=85, b=170;
DDRB = 1<<DDB4 | 1<<DDB1 | 1<<DDB0;
TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
TCCR0B = 0<<WGM02 | 3<<CS00;
TCCR1 = 0<<PWM1A | 0<<COM1A0 | 7<<CS10;
GTCCR = 1<<PWM1B | 2<<COM1B0;
OCR1C = 255;
for (;;)
{
OCR0A = r++;
OCR0B = g++;
OCR1B = b++;
_delay_ms(10);
}
โอ้โห ให้ code หมดเลย ขอบคุณมากๆครับ
ปกติ ผมไล่ code คนอื่นแล้วมักจะงง เพราะขี้เกียจนั่งไล่ว่า ตัวแปร r b หรือ g มันคืออะไร
เลยชอบนั่งขุดจาก datasheet เอง ค่อยตามได้หน่อย
อย่างไรก็ดี ขอบคุณมากครับ
วิธีของ อ Jmew ก็ว่ากันตาม Bascom เคยใช้ แต่... ไม่ได้แตะมานานแล้ว ลืมไปหมดแล้ว :-[
Quote
ปกติ ผมไล่ code คนอื่นแล้วมักจะงง เพราะขี้เกียจนั่งไล่ว่า ตัวแปร r b หรือ g มันคืออะไร
เลยชอบนั่งขุดจาก datasheet เอง ค่อยตามได้หน่อย
จริงๆผมมองว่าเราไม่จำเป็นต้อง coding ใหม่หมดเลยทุกอย่าง โดยเฉพาะการ programming แบบต่อยอดผมมองว่าพัฒนาไปได้เร็วกว่าการที่เรานั่ง coding เองหมดทุกอย่างครับ ;)
Quote
จริงๆผมมองว่าเราไม่จำเป็นต้อง coding ใหม่หมดเลยทุกอย่าง โดยเฉพาะการ programming แบบต่อยอดผมมองว่าพัฒนาไปได้เร็วกว่าการที่เรานั่ง coding เองหมดทุกอย่างครับ ;)
ครับ เห็นด้วยในแง่ของผู้ที่ต้องผลิตชิ้นงาน หรือประกอบอาชีพด้านนี้
ผมสนใจในแง่ที่ "อยากรู้" และ ที่มาที่ไป( mechanic กลไกใส้ใน ของการทำงานของ microcontroller )
จากมุมมองของ
ผู้เล่นเป็นงานอดิเรก และมีความสนุกสนานกับการเรียนรู้ของมันมากๆ
และโดยเฉพาะอย่างยิ่ง เมื่อได้เห็นผลงานจริงของเรา จากที่ได้อ่านและทำเอง
( แปลว่า ทำทดลองบอร์ด เขียน Code "เอง" ให้มันทำตามที่เราต้องการ ) เมือได้ผล ก็แปลว่า เราเข้าใจเนื้อในใส้พุงของมัน สนุกกว่าการไปลอก code เขามา
ประการสำคัญ ผมถูกพ่อแม่สอนให้หัดทำอะไรเองตั้งแต่เด็ก :'( ( ในเรื่องที่พอทำเองได้ )
และที่ผ่านมาหลายปี ก็มีความสนุกกับงานอดิเรกใหม่ ( mcu & electronics ) มาก แม้จะมีเรื่องต้องเรียน อีกแยะมากกกกกกกกกกกกกกกกกกก
ขอบคุณมาก สำหรับความคิดเห็นครับ ;D