29、PIC通信与实时时钟编程详解

PIC通信与实时时钟编程详解

1. PIC间UART通信原理与程序分析

PIC(Peripheral Interface Controller)微控制器可利用通用异步收发传输器(UART)与终端设备进行通信。在PIC - PIC UART项目中,两个PIC通过UART实现信息交互。

1.1 程序原理
  • 两个PIC首先在LCD上显示开场语句。
  • 接着进入无限循环。PIC1等待重复按钮变高后,若PIC2将CTS输入驱动到逻辑‘0’,则向PIC2发送第一条消息“Hi”。
  • 发送消息后,设置约135ms的延迟,确保重复按钮回到逻辑‘0’。
  • 再次等待重复按钮变高,PIC1才能发送下一条消息。在此之前,PIC2应发送其第一条消息。
  • 此过程不断重复,PIC1接收PIC2的两条消息,并向PIC2发送自己的消息。
1.2 PIC2程序代码
/*This is a basic program to use the UART
To communicate with two PICs
This is the program for PIC two
Written by H H Ward for the PIC18F4525
Dated 03/04/2021*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <4bitLCDDemoBoard.h>
unsigned char n, count, newdatain = 0;
unsigned char mess[30], *messpointer;
#define repeatButton PORTAbits.RA4
#define RTS PORTBbits.RB0
#define CTS PORTBbits.RB1

void shortdelay ()
{
    TMR0 = 0;
    while (TMR0 < 255);
}

void delay (unsigned char t)
{
    for (n = 0; n < t; n ++)
    {
        TMR0 = 0;
        while (TMR0 < 255);
    }
}

void sendDeviceString(const char* meshw)
{
    while(*meshw)
    {
        while (CTS);
        RTS = 1;
        while(!TXIF);
        TXREG = (*meshw++);
        shortdelay ();
        RTS = 0;
    }
}

void interrupt  isr1 ()
{
    if (PIR1bits.RCIF == 1)
    {
        RTS = 1;
        do
        {
            if(OERR)
            {
                CREN = 0;
                CREN = 1;
            }
            while(!RCIF);
            newdatain = RCREG;
            lcdData = newdatain;
            lcdOut ();
            shortdelay ();
        }while (RCIF);
        RTS = 0;
    }
}

void main ()
{
    PORTA = 0;
    PORTB = 0;
    PORTC = 0;
    PORTD = 0;
    TRISA = 0b00010000;
    TRISB = 0x02;
    TRISC = 0b10000000;
    TRISD = 0x00;
    ADCON0 = 0x00;
    ADCON1 = 0x0F;
    OSCCON = 0b01110000;
    OSCTUNE = 0b10000000;
    T0CON = 0b11000111;
    INTCON = 0b11000000;
    PIE1bits.RC1IE = 1;
    TXSTA = 0b00100000;
    RCSTA = 0b10010000;
    BAUDCON = 0b00000000;
    SPBRG = 12;
    messpointer = mess;
    setUpTheLCD ();
    clearTheScreen ();
    writeString ("Coded PIC2");
    line2 ();
    while (1)
    {
        while (repeatButton);
        while (CTS);
        sendDeviceString ("Hello");
        delay (10);
        while (repeatButton);
        while (CTS);
        sendDeviceString ("OK Will Do");
        delay (10);
        while (repeatButton);
        delay (10);
    }
}
2. 实时时钟(RTC)编程

实时时钟(RTC)在许多应用中至关重要,可用于同步事件、创建日历等。以下介绍使用PIC18F4525实现RTC的方法。

2.1 RTC原理

使用外部32.768kHz晶体振荡器作为timer1的时钟源,timer1设置为16位定时器,用于计数时钟脉冲。

2.2 T1CON控制寄存器

T1CON控制寄存器的各比特位功能如下:
| 比特位 | 功能 | 说明 |
| ---- | ---- | ---- |
| 7 RD16 | 16位读写模式使能位 | 逻辑‘1’:TMR1作为16位读写操作;逻辑‘0’:TMR1作为8位读写操作 |
| 6 T1RUN | 定时器1系统时钟状态位 | 逻辑‘1’:设备时钟源自timer1振荡器;逻辑‘0’:设备时钟源自其他地方 |
| 5 T1CKPS1 | 定时器1时钟预分频选择1 | 与T1CKPS0配合使用 |
| 4 T1CKPS0 | 定时器1时钟预分频选择0 | 与T1CKPS1配合使用,提供四种不同分频比 |
| 3 T1OSCEN | 定时器1振荡器使能位 | 逻辑‘1’:timer1振荡器启用;逻辑‘0’:振荡器禁用 |
| 2 T1SYNC | 定时器1外部时钟输入同步选择位 | 依赖于TMR1CS位,TMR1CS为‘1’时,逻辑‘1’:不同步外部时钟输入;逻辑‘0’:同步外部时钟输入 |
| 1 TMR1CS | 定时器1时钟源选择位 | 逻辑‘1’:外部时钟;逻辑‘0’:内部时钟(Fosc/4) |
| 0 TMR1ON | 定时器1开启位 | 逻辑‘1’:开启timer1;逻辑‘0’:关闭timer1 |

定时器1时钟预分频比设置如下:
| T1CKPS1 | T1CKPS0 | 预分频比 |
| ---- | ---- | ---- |
| 0 | 0 | 1:1 不分频 |
| 0 | 1 | 1:2 二分频 |
| 1 | 0 | 1:4 四分频 |
| 1 | 1 | 1:8 八分频 |

为使用外部晶体振荡器作为timer1的时钟源,需将T1CON设置为0b00001111,具体操作如下:
- 位0设置为逻辑‘1’,开启timer1。
- 位1设置为逻辑‘1’,使用外部振荡器作为timer1的时钟源。
- 位2设置为逻辑‘1’,不同步外部时钟输入。
- 位3设置为逻辑‘1’,启用外部振荡器电路。
- 位4和5设置为逻辑‘0’,不分频振荡器。
- 位6设置为逻辑‘0’,设备时钟不源自timer1振荡器。
- 位7设置为逻辑‘0’,timer1寄存器由两个8位寄存器TMR1H和TMR1L级联组成。

2.3 RTC程序代码
/*
* File:   Real Time Clock.c
Author: H. H. Ward
*Written for the PIC18F4525
Created on 24 August 2020, 12:09
*/
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <4bitLCDDemoBoard.h>
unsigned char secunits = 0X30, sectens = 0X30, minunits = 0X30, mintens = 0X30, hourunits = 0X30, hourtens = 0X30;

void delay (unsigned char t)
{
    for (n = 0; n < t; n ++)
    {
        TMR0 = 0;
        while (TMR0 < 255);         //a 30msec delay
    }
}

void interrupt isr1 ()
{
    secunits ++;
    PIR1bits.TMR1IF = 0;
    TMR1H = 0X80;
}

void main ()
{
    PORTA = 0;
    PORTB = 0;
    PORTC = 0;
    PORTD = 0;
    TRISA = 0b00001111;
    TRISB = 0b00000000;
    TRISC = 0b10010010;
    TRISD = 0x00;
    ADCON0 = 0b00000000;
    ADCON1 = 0b00001111;
    OSCTUNE = 0x80;
    OSCCON = 0x70;
    T0CON = 0XC7;
    T1CON = 0b00001111;
    INTCON = 0b11000000;
    PIE1bits.TMR1IE = 1;
    PORTB = 0;
    setUpTheLCD ();
    writeString ("Hello");
    line2 ();
    while (1)
    {
        if (secunits == 0X3A)
        {
            secunits = 0X30;
            sectens ++;
            if ( sectens == 0X36)
            {
                sectens = 0X30;
                minunits ++;
                if (minunits == 0X3A)
                {
                    minunits = 0X30;
                    mintens ++;
                    if (mintens == 0X36)
                    {
                        mintens = 0X30;
                        hourunits ++;
                        if(hourunits == 0X3A)
                        {
                            hourunits = 0X30;
                            hourtens ++;
                        }
                    }
                }
            }
        }
        if (hourtens == 0X32 & hourunits == 0X34 )
        {
            hourtens = 0x30;
            hourunits= 0x30;
        }
        line2 ();
        lcdData = hourtens;
        lcdOut ();
        lcdData = hourunits;
        lcdOut ();
        lcdData = 0x3A;
        lcdOut ();
        lcdData = mintens;
        lcdOut ();
        lcdData = minunits;
        lcdOut ();
        lcdData = 0x3A;
        lcdOut ();
        lcdData = sectens;
        lcdOut ();
        lcdData = secunits;
        lcdOut ();
        lcdData = 0xA0;
        lcdOut ();
    }
}
2.4 RTC程序分析
  • 主原理 :使用timer1计数外部晶体振荡器的时钟脉冲,timer1设置为16位定时器,计数结果存储在TMR1H和TMR1L中。
  • 计数时间计算 :外部晶体振荡器频率为32.768kHz,一个计数周期为30.5176ms,计数从0到65535需要2秒。为实现1秒计数,让timer1从0b1000000000000000开始计数。
  • 中断处理 :当timer1计数达到最大值并溢出时,TMR1IF标志位设置为逻辑‘1’。为利用此溢出事件,需启用timer1中断,包括全局中断和外设中断。
  • 中断服务例程(ISR) :在ISR中,将secunits变量加1,清除TMR1IF标志位,并将TMR1H加载为0X80,使timer1从后半部分开始计数。
  • LCD显示 :在无限循环中,检查secunits的值,若达到0X3A(ASCII码为10),则将其重置为0X30,并将sectens加1。类似地,处理分钟和小时的进位。最后,将时间信息发送到LCD显示。

以下是RTC程序的流程:

graph TD;
    A[初始化] --> B[开启全局和外设中断];
    B --> C[设置timer1];
    C --> D[等待timer1溢出中断];
    D --> E[执行中断服务例程];
    E --> F[更新时间变量];
    F --> G[检查进位];
    G --> H[更新LCD显示];
    H --> D;

通过以上分析,我们详细了解了PIC间UART通信和实时时钟编程的原理与实现方法。这些技术在嵌入式系统开发中具有重要应用价值,可用于实现各种时间敏感的功能。

3. 关键技术点总结与操作步骤梳理
3.1 PIC间UART通信关键技术点
  • 信号交互 :PIC1和PIC2通过CTS(清除发送)和RTS(请求发送)信号进行通信协调。PIC2将CTS输入驱动到逻辑‘0’时,PIC1才能发送消息。
  • 延迟设置 :发送消息后设置延迟,确保重复按钮回到逻辑‘0’,避免误操作。
  • 消息发送 :使用 sendDeviceString 函数发送字符串消息,发送过程中会等待CTS信号为低,并设置RTS信号为高。
3.2 PIC间UART通信操作步骤
  1. 初始化设置 :对端口、寄存器等进行初始化,如设置 PORTA PORTB 等为初始值,配置 TRISA TRISB 等端口方向。
  2. LCD初始化 :调用 setUpTheLCD clearTheScreen 函数初始化LCD,并显示开场语句。
  3. 进入循环 :在无限循环中,等待重复按钮变高,检查CTS信号,发送消息,设置延迟。

以下是PIC - PIC UART通信的操作步骤流程图:

graph TD;
    A[初始化设置] --> B[LCD初始化];
    B --> C[进入无限循环];
    C --> D[等待重复按钮变高];
    D --> E[检查CTS信号];
    E --> F{CTS为低?};
    F -- 是 --> G[发送消息];
    F -- 否 --> D;
    G --> H[设置延迟];
    H --> D;
3.3 RTC编程关键技术点
  • 时钟源选择 :使用外部32.768kHz晶体振荡器作为timer1的时钟源,确保时钟精度。
  • 中断处理 :利用timer1溢出中断来更新时间变量,实现精确计时。
  • 时间进位处理 :在无限循环中检查时间变量的进位情况,确保时间显示的正确性。
3.4 RTC编程操作步骤
  1. 初始化设置 :对端口、寄存器等进行初始化,如设置 PORTA PORTB 等为初始值,配置 T1CON 寄存器。
  2. 启用中断 :设置 INTCON PIE1bits.TMR1IE 启用全局中断和timer1外设中断。
  3. LCD初始化 :调用 setUpTheLCD writeString 函数初始化LCD并显示初始信息。
  4. 进入循环 :在无限循环中,检查时间变量的进位情况,更新LCD显示。
4. 代码优化建议
  • PIC间UART通信代码优化
    • 延迟优化 :可以根据实际情况调整延迟时间,避免不必要的等待。
    • 错误处理 :在消息发送和接收过程中增加错误处理机制,提高通信的稳定性。
  • RTC编程代码优化
    • 时间设置功能 :增加时间设置功能,允许用户手动设置时钟时间。
    • 显示优化 :优化LCD显示格式,提高显示的可读性。
5. 总结

本文详细介绍了PIC间UART通信和实时时钟(RTC)编程的原理、程序代码和操作步骤。通过对PIC - PIC UART通信的分析,我们了解了如何通过UART实现两个PIC之间的信息交互;通过对RTC编程的讲解,我们掌握了如何使用外部晶体振荡器和timer1实现精确的实时时钟功能。这些技术在嵌入式系统开发中具有广泛的应用前景,可用于实现各种时间敏感的功能,如事件同步、日历管理等。在实际应用中,我们可以根据具体需求对代码进行优化,提高系统的性能和稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值