ออกแบบ Power save mode dsPIC

ลองออกแบบลดพลังงาน MCU dsPIC30F4011 ให้ใช้กับ Battery 9V โดยออกแบบทั้ง Software และ Hardware ให้ประหยัดพลังงานแบบสุดๆ

ตั้งค่า TRIS register กำหนดให้เป็น Output จะกินไฟน้อยกว่า Config เป็น Input

TRISB = 0;
TRISC = 0;
TRISD = 0;
TRISE = 0;
TRISF = 0;

ลองวัดกระแสดูแล้วกินไฟสถานะ Idle เฉพาะ dsPIC เพียง 19 uA ก็กินไฟน้อย แต่คงไม่เท่ากับ TI

เทคนิคการขยาย Port Output ด้วย Shift Register

สำหรับ MCU เบอร์เล็กๆ ที่มีขา I/O ไม่มากนัก เช่น 89C2051 ถ้าเราต้องการขยาย Port แบบ Output ให้ได้เยอะๆ เช่นต้องการจะต่อ 7 Segment ซัก 30 ตัว ถึงจะใช้วิธี Scan Display ก็เถอะ ลองคำนวนดู ใช้ 8 bit สำหรับ data 7 segment และในแต่ละตัวก็ต้อง มีขา Common อีก สรุปว่าคงไม่พอครับ

เทคนิคหนึ่งที่นิยมใช้ก็คือใช้ Shift register ในการขยาย Port โดยเราจะใช้ขา data เพียง 3 ขาเท่านั้น Clock, Data,Strobe IC แต่ละผู้ผลิตอาจจะตั้งชื่อขาสัญญาณแตกต่างกันไปบ้างแต่หลักการเดียวกัน โดย Data จะส่งไปพร้อมกับ Clock หรือที่เรียกการส่งข้อมูลแบบนี้ว่า Synchronous

การต่อสาย 74HC595 แบบอนุกรมหลายตัว

IC ที่นิยมนำมาใช้จะเป็นเบอร์ที่ลงท้ายด้วย 595 เช่น 74HC595, 74LS595, TPIC6B595(Open Collector) การต่อใช้งานขา Data จาก MCU จะต่อเข้ากับ Data in ของตัวที่ 1 และ Data Out ของตัวที่ 1 จะต่อเข้ากับ Data in ของตัวที่ 2 เป็นอย่างนี้ไปเรื่อยๆจนถึงตัวสุดท้าย Data Out ของตัวสุดท้ายจะไม่ถูกต่อ

IC Shift register ตระกูล 595

สำหรับ Code ตัวอย่างนี้ สามารถนำไปประยุกต์ใช้ได้ทุกตระกูล MCS51, AVR, PIC หรือตระูกูลอื่นๆ

อธิบายฟังก์ชัน

Code นี้ต่อ 74HC595 ไว้ 4 ตัวอนุกรมกัน ใน 1 ตัว ตัวแปร Hc595[0] แทน 74HC595 ตัวที่ 1 ไปเรื่อยๆ จนถึง Hc595[3] แทน 74HC595 ตัวที่ 4 การเขียนข้อมูลในแต่ละ byte จะใช้ฟังก์ชัน void wrport8 (unsigned char dat) การส่งข้อมูลไปยัง 74HC595 ทั้ง 4 ตัวใช้ฟังก์ชัน void wrport() เริ่มจาก ให้ OE595 และ STR เป็น “0″ จากนั้นก็ส่งข้อมูล Hc595[0]…Hc595[3] ตอนนี้ข้อมูลจะถูกเก็บไว้ใน D-flipflop ใน 74HC595 แล้ว แต่ยังไม่ถูกส่งออกมายัง Port ข้อมูลจะถูกส่งออกมายัง Port หลังจากส่ง Pulse ไปยัง STR

Code Example

#define SCK_DDR ??DDRB.3??//????????????
#define SDO_DDR ??DDRB.2??//
#define STR_DDR ??DDRB.1??//??
#define OE595_DDR ??DDRB.0??//??#define SCK ???PORTB.3??//
#define SDO ???PORTB.2??//??
#define STR ???PORTB.1??//?????
#define OE595 ???PORTB.0??//??

//—————————————————————————
// Write serial data
//—————————————————————————
void wrport8 (unsigned char dat)
{
?unsigned char cnt,a;
?for (cnt = 0;cnt < 8;cnt++){
??if (dat & 0×80)
???SDO = 1;
??else
???SDO = 0;
??dat <<= 1;
??a = 5;?while(a)?a–;
??SCK = 1;
??a = 5;?while(a)?a–;
??SCK = 0;
?}
}
//—————————————————————————
// Write serial data
//—————————————————————————
void wrport()
{???????????
//?unsigned char a;
?OE595 = 0;
?STR = 0;

? ?wrport8(Hc595[0]);
?wrport8(Hc595[1]);
? ?wrport8(Hc595[2]);
?wrport8(Hc595[3]);?

?STR = 1;????
?STR = 1;?
?STR = 1;?
//?a = 10;?while(a)?a–;
?STR = 0;
}?

การทดลองที่ 3 เทคนิคการเก็บข้อมูล Long, Float ลง EEPROM ด้วยวิธี UNION

การเก็บข้อมูลที่มีขนาดมากกว่า 1 Byte เราสามารถทำได้ประมาณ 3 วิธี

1. ทำการแบ่ง Byte ข้อมูลเป็นส่วนๆ ด้วยการหารเช่นกรณี unsigned int ถ้าเราหารด้วย 256 ก็จะได้ตัวแปร Byte High ถ้าเรา mod ด้วย 256 ก็จะได้ตัวแปร Byte Low จากนั้นก็เอาตัวแปรแต่ละตัวไปเก็บไว้ใน EEPROM วิธีนี้จะเสีย CYCLE ในการประมวลผลไปเปล่าๆ

2. ใช้ Pointer เราประกาศ Pointer เป็น char แล้วก็เลื่อน Pointer ไปทีละ 1 ไบต์ก็จะได้ตัวแปรแต่ละไบต์

3. ใช้ UNION วิธีนี้เป็นวิธีที่ผมใช้บ่อย ก่อนที่จะอธิบายการจัดเก็บ ผมขออธิบาย UNION ก่อนว่า UNION คืออะไร

UNION เป็นการประกาศตัวแปรที่ใช้หน่วยความจำร่วมกัน ตัวแปรที่ประกาศแบบ UNION จะมีหน่วยความจำอยู่ตำแหน่งทับกันหมดทุุกตัว เช่นตัวอย่างตัวแปร Dat_long.word ใช้ตำแหน่งหน่วยความจำเดียวกัน การแก้ไขตัวแปร Dat_long.word ก็จะมีผลกับตัวแปร Dat_long.byte[0-3]

รูปที่ 1 memory จากการใช้คำสั่ง UNION

รูปที่ 2 Schematic ที่ใช้ในการทดลอง 3

การประยุกต์ใช้งานกับหน่วยความจำ เพียงย้ายข้อมูลมาไว้ Float, long แล้ว เอาข้อมูลจากตัวแปร์ array มาเก็บไว้ใน EEPROM

//***************************************************************************//
//Project : union.mcp
//Description : Union
//Device : PIC16F873A
//By : ThaiEmbedded 2006
//Date : 25 Nov 2006
//***************************************************************************//#include <pic.h>
#include <stdio.h>
#include <stdlib.h>

__CONFIG(XT & WDTDIS & PWRTEN & BORDIS & LVPDIS & DEBUGDIS & UNPROTECT);

long ee_buff[2];

union dat_long
{
unsigned char byte[4];
long word;
}Dat_long;
union dat_long Dat_long;
//——————————————————————————//
// Delay (mSec)
//——————————————————————————//
void dmsec (unsigned int Count)
{

unsigned char i;
while (Count)
{
for (i=0;i<=100;i++);
Count–;
}
}
//——————————————————————————//
// Main Program
//——————————————————————————//
void main ()
{
dmsec(200);
TRISB = 0b00000000; //Output mode

ee_buff[0] = 123456;
Dat_long.word = ee_buff[0];
EEPROM_WRITE(0, Dat_long.byte[0]);
EEPROM_WRITE(1, Dat_long.byte[1]);
EEPROM_WRITE(2, Dat_long.byte[2]);
EEPROM_WRITE(3, Dat_long.byte[3]);

dmsec(200);
Dat_long.word = 0;

Dat_long.byte[0] = EEPROM_READ(0);
Dat_long.byte[1] = EEPROM_READ(1);
Dat_long.byte[2] = EEPROM_READ(2);
Dat_long.byte[3] = EEPROM_READ(3);

ee_buff[1] = Dat_long.word;

if(ee_buff[0]==ee_buff[1])
PORTB = 1;
else
PORTB = 3;

while(1); //Loop Forever
}

แบบฝึกหัด

ลองเปลี่ยนตัวแปรจาก Long เป็น float ลอง Compile ดูว่า ให้ผลลัพท์เหมือนเดิมไหม

Download Code การทดลองที่ 3