السلام عليكم
العفو أخي بارك الله فيك.
أخي قبل أن أقوم بالرد السابق عملت المثال أولا بالتايمر 0 ثم بالتايمر 1 ولاحظت
أن التايمر 1 أكثر دقة .
ربما لان التايمر 0 مسجل ب8 بت فقط بينما التايمر 1 مسجل ب16 بت
تفضل نفس المثال لكن بالتايمر0:
كود:
// Pic16F628A - osc:4Mhz
unsigned int ms_counter =0;
unsigned int s_counter =0;
//Timer0
//Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer0(){
OPTION_REG = 0x81; //or: 0b10000001;
TMR0 = 6;
INTCON = 0xA0; //or: 0b10100000;
}
void Interrupt(){
if (TMR0IF_bit){
TMR0IF_bit = 0;
TMR0 = 6;
//Enter your code here:
///////////////////////////////////////:
ms_counter++;
if (ms_counter == 1000)
{
ms_counter = 0;
s_counter ++;
}
if (s_counter == 5)
{
portb.b0 = 0;
}
if (s_counter == 15)
{
s_counter = 0;
portb.b0 = 1;
}
///////////////////////////////////////.
}
}
void main()
{
cmcon = 7;
trisb.b0 = 0; portb.b0 = 1;
InitTimer0();
while (1)
{
}
}
لاحظ أن زمن المقاطعة هذه المرة 1ms
وبما أن 1 تانية يساوي 1000 ميلي تانية يجب على العداد ms_counter أن يعد 1000 مرة في كل دورة.
ملفات المثالين :
ملفات التايمر 0 + ملفات التايمر1:
https://up.top4top.net/downloadf-758jjl171-rar.html
المحاكاة ببروتوس 8.5
أرجو أن يفيدك ما سبق
وإذا كانت لديك استفسارات تفضل..
|
متابعة لما سبق:
1- بخصوص الطريقة والخطوات في برنامج حاسب التايمر فهي نفسها لجميع التايمرات .
الاختلاف طبعا في التعليمات فكل تايمر يشتغل بمسجلات مختلفة عن النوع الآخر.
التايمر0 مثلا يشغل المسجلين الشهيرين option_reg و intcon
البرنامج وضع أمام كل واحد منهما القيمة بالسادس عشري هكّذا :
كود:
OPTION_REG = 0x81;
INTCON = 0xA0;
لاحظ أخي أني وضعت لك أمام القيمة بالسادس عشري ما يقابلها بالتنائي في مكان التعاليق طبعا.
وهذا حتى تتمكن ، لو كنت تحب تتعمق في البحث عن أصل الأشياء ، من معاينة المسجلين في الداتا شيت وتتعرف على كل bit منهما وما هو دوره عندما يكون 0 وما دوره عندما يكون 1.
وخاصة بالنسبة للمسحل OPTION_REG وبالأخص البتات الثلاث الاولى (ابتداء من اليمين) والبت الرابع .
2- خطوات استخدام التيمر0:
1*
إعدادات برنامج الحاسب:

2*
كود المقاطعة الذي أنتجه البرنامج هو:
كود:
//Timer0
//Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer0(){
OPTION_REG = 0x81;
TMR0 = 6;
INTCON = 0xA0;
}
void Interrupt(){
if (TMR0IF_bit){
TMR0IF_bit = 0;
TMR0 = 6;
//Enter your code here
}
}
بمذبذب 4 ميغاهرتز كان الناتج هو :مقطعة كل 1 ميللي تانية
يعني للحصول عل 1 تانية لازم عداد يحسب 1000 مرة (1s = 1000ms).
في المثال العداد المقصود سبق أن وضعت له اسما هو ms_counter.
3*
الان بعد حصولي على كود المقاطعة ، أذهب الى صفحة المشروع بالميكروسي.
تظهر بهذه الكتابة وهي الدالة الرئيسية لأي مشروع:
فوق هذه الدالة أي في مكان التعريفات بأعلى الصفحة
أضع المتغيرين المستخدمين :
كود:
unsigned int ms_counter =0;
unsigned int s_counter =0;
void main() {
}
4*
ما بين تعريف المتغيرين والدالة الرئيسية أنسخ كود المقاطعة الذي حصلت عليه من البرنامج:
ستبدو صفحة الميكروسي هكذا:
كود:
unsigned int ms_counter =0;
unsigned int s_counter =0;
//Timer0
//Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer0(){
OPTION_REG = 0x81;
TMR0 = 6;
INTCON = 0xA0;
}
void Interrupt(){
if (TMR0IF_bit){
TMR0IF_bit = 0;
TMR0 = 6;
//Enter your code here
}
}
void main() {
}
5*
الآن لنتذكر الكود البسيط لحساب الميلي تواني وحساب التواني و 15 تانية الذي سبق لي كتابته :
كود:
///////////////////////////////////////:
ms_counter++;
if (ms_counter == 1000)
{
ms_counter = 0;
s_counter ++;
}
if (s_counter == 5)
{
portb.b0 = 0;
}
if (s_counter == 15)
{
s_counter = 0;
portb.b0 = 1;
}
///////////////////////////////////////.
في صفحة المشروع بالميكروسي يجب وضعه تحت هذا السطر:
//Enter your code here
الى هنا تظهر الصفحة هكذا:
كود:
unsigned int ms_counter =0;
unsigned int s_counter =0;
//Timer0
//Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer0(){
OPTION_REG = 0x81; //or: 0b10000001;
TMR0 = 6;
INTCON = 0xA0; //or: 0b10100000;
}
void Interrupt(){
if (TMR0IF_bit){
TMR0IF_bit = 0;
TMR0 = 6;
//Enter your code here:
///////////////////////////////////////:
ms_counter++;
if (ms_counter == 1000)
{
ms_counter = 0;
s_counter ++;
}
if (s_counter == 5)
{
portb.b0 = 0;
}
if (s_counter == 15)
{
s_counter = 0;
portb.b0 = 1;
}
///////////////////////////////////////.
}
}
void main()
{
}
6* يبقى فقط إدراج تعليمات معروفة توضع داخل الدالة الرئيسية
مع التنبيه إلى تعليمة النداء على دالة التايمر0 وهي التعليمة:
فيصبح الكود كاملا هكذا:
كود:
// Pic16F628A - osc:4Mhz
unsigned int ms_counter =0;
unsigned int s_counter =0;
//Timer0
//Prescaler 1:4; TMR0 Preload = 6; Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer0(){
OPTION_REG = 0x81; //or: 0b10000001;
TMR0 = 6;
INTCON = 0xA0; //or: 0b10100000;
}
void Interrupt(){
if (TMR0IF_bit){
TMR0IF_bit = 0;
TMR0 = 6;
//Enter your code here:
///////////////////////////////////////:
ms_counter++;
if (ms_counter == 1000)
{
ms_counter = 0;
s_counter ++;
}
if (s_counter == 5)
{
portb.b0 = 0;
}
if (s_counter == 15)
{
s_counter = 0;
portb.b0 = 1;
}
///////////////////////////////////////.
}
}
void main()
{
cmcon = 7;
trisb.b0 = 0; portb.b0 = 1;
InitTimer0();
while (1)
{
}
}
أو بعد تخليصه من الزوائد:
كود:
// Pic16F628A - osc:4Mhz
unsigned int ms_counter =0;
unsigned int s_counter =0;
//Timer0
void InitTimer0(){
OPTION_REG = 0x81; //or: 0b10000001;
TMR0 = 6;
INTCON = 0xA0; //or: 0b10100000;
}
void Interrupt(){
if (TMR0IF_bit){
TMR0IF_bit = 0;
TMR0 = 6;
ms_counter++;
if (ms_counter == 1000)
{
ms_counter = 0;
s_counter ++;
}
if (s_counter == 5)
{
portb.b0 = 0;
}
if (s_counter == 15)
{
s_counter = 0;
portb.b0 = 1;
}
}
}
void main()
{
cmcon = 7;
trisb.b0 = 0; portb.b0 = 1;
InitTimer0();
while (1)
{
}
}