通信系统工程实践报告

姓名:

学号:

学院:信息学院

专业:通信工程

指导老师:

时间:2015年12月22日

通信系统工程实践报告

一、创建一个新的工程

1. Project →Project Wizard…→点击下一步→选择芯片→选择Toolsuite

并确保没有打叉,设置储存位置→点击下一步→创建新的工程文件,选择一个文件夹,确定后即可在这个文件家里找到自己创建的工程→添加文件或稍后创建文件后添加→完成。

2.File →New(或点击快捷栏New File 图标) →无论是.h 还是.c 文件,编辑完成后保存,保存时即可选择保存为.h 还是.c →往文件夹中添加刚刚保存的.h 、.c 文件即可

二、串口通信实验:

1)步骤

1、将IDE 3、Explorer 16主板、音频子板、音频线、扩音器、电脑连接好,打开主板电源;

2、打开MPLAB ,点击File →Open Workspace →DTMF_710A_ASM_REV - OK →dtmf_gen.mcw

3、此时,界面将出现层层叠叠的许多窗口,现在,点击Window →Tile Horizontally使各窗口水平排列或点击Window →Tile Vertically使各窗口垂直排列;

4、点击Programmer →Select Programmer→MPLAB ICD 3;

5、点击Project →Build All或点击快捷菜单栏中的Build All按钮,如果出现语言工具选择对话框,则一律选择上方的Use this;

6、点击Programmer →Program ,开始烧录程序;

7、打开串口调试助手,选择电脑此时的串口(打开设备管理器即可看到是哪一个COM 口;波特率选择19200;

8、在输入框中输入#*012~9字符,点击手动发送,则看到界面显示了输入的内容,主板上的显示频同样显示了输入的内容,同时听到拨号音。

9、将自动发送打钩,串口调试助手将自动循环发送输入的内容。减小自动发送周期,原本清晰连续的拨号音将变快,继续减小周期,将变成不断地噪音;

2)问题发现

1.Buil All 失败。

2. 通过实验发现,每次只能返回输入内容的前8位。

3. 在在自己的电脑上安装MPLAB 后打不开工作区。

3)问题解决

1. 对于Build All失败:点击Project →Select Language Tool Location→Microchip C30

Toolsuite 。

2. 对于只返回前8位:将串口调试助手的数据位由8位改至10位依然只返回前8位而不是前10位。再改为6位时,只返回前6位。由此可知,仅返回8位不仅和串口调试助手这款软件有关,还与实验程序有关,由于能力有限,我没有找到具体原因。

3. 对于打不开工作区文件,检查是否安装mplabc30-v3_31-windows-installer.exe,检查安装路径是否正确,检查工作区文件路径是否含有中文等或违规字符,经检查,问题出在我将工作区文件放在了一个中文名文件夹下,导致软件不能识别,修改后顺利打开。

三、 MPLAB 使用心得

1. 程序#Include 中modems.h 在file 窗口中未找到,这时可以在文件夹中搜索

2. 修改字体、字形、大小:Eidt →Properties... →Text →Select Font →在这个窗口中,即可修

改字体等参数,选择合适的字大小能方便阅读程序。

其实Eidt →Properties... 有更多功能,现例举如下:

3、在C File Types选项卡中,选中Line number,可以显示代码行序号,方便查看;

4、在C File Types选项卡中,取消Double click toggles breakpoint选项,可以取消双击鼠标设置断点,代替为双击选中选取单词,再次双击选取整行;

5、在C File Types选项卡中,选中Enable Code Floding选项,可以实现代码折叠功能;

6、在Tools tips 选项卡中,选中AutoComplete 下面的几个选项,可以在输入源代码的时候自动提示函数集结构体。

7、选中use tabedd window,实现可使打开地多个源文件,显示在一个标签栏上, 方便源文件切换。

8、Window 中Tile Horizontally/Vertically可以使窗口水平/垂直排列,方便浏览。效果如下:

四、dsPIC33F Demo for Explorer 16 Board程序理解

总体理解:程序始终在执行hours 、minutes 、seconds 的加法工作,由hexdec.c 程序提取出时分秒的十位数和个位数,再由一些汇编语言结合LATD 、TRISA 等寄存器使LCD 显示数字。本程序选择了带PLL 的在XT 晶振模式下的主振荡器,即使用了内置8MHz 的FRC 震荡器,分频后产生的FOSC 为32.4MHz 。由此获得了200us 、1ms 、2ms 、5ms 、15ms 以及1s 的延时。通过延时使得时分秒间隔各自所需延时加一,提取了十位数和个位数后再显示到了LCD 屏上。于是实现了实时时钟功能。

以下为详细程序理解(粗体为源程序,其余为我的理解):

_FOSCSEL(FNOSC_PRIPLL);

_FOSC(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMD_XT);

_FWDT(FWDTEN_OFF);

在p33FJ256GP710A.h 中可查到如下定义:

#define FNOSC_PRIPLL 0xFFFB

转化为2进制:[**************]1,查手册知选用带PLL 的主(XT 、HS 或EC )振荡器

所以FNOSC_PRIPLL为带PLL 的主(XT 、HS 或EC )振荡器

#define FCKSM_CSDCMD 0xFFBF

转化为二进制:[**************],查手册知:FCKSM_CSDCMD为禁止时钟切换,禁止故障保护时钟监视器

#define OSCIOFNC_OFF 0xFFFF

转化为二进制:[**************]1查手册知OSCIOFNC_OFF表示 SC2 为时钟输出 #define POSCMD_XT 0xFFFD

转化为二进制:[**************]1查手册知POSCMD_XT为XT 晶振模式

#define FWDTEN_OFF 0xFF7F

转化为二进制:[**************]1查手册知FWDTEN_OFF即为通过用户软件使能/ 禁止看门狗定时器(可通过清零RCON 寄存器中的SWDTEN 位来禁止LPRC )

于是这三条语句实现的功能是:选用带PLL 的主(XT 、HS 或EC )振荡器,禁止时钟切换,禁止故障保护时钟监视器,SC2 为时钟输出,XT 晶振模式,通过用户软件使能/ 禁止看门狗定时器(可通过清零RCON 寄存器中的SWDTEN 位来禁止LPRC )

PLLFBD = 0x00A0;//给PLL 寄存器写入10100000

CLKDIV = 0x0048;//给ClDDIV 寄存器写入1001000

查手册中PLLFBD 寄存器表以及CLKDIV 表可知:

PLLFBD(PLL 反馈分频比寄存器) = 0x00A0; //10100000 162

bit 15-9 未实现:读为0

bit 8-0 PLLDIV:PLL 反馈分频比位(也表示为“M ”,PLL 倍频比)

010100000=162;

CLKDIV(时钟分频比寄存器) = 0x0048;//1001000

bit 15 ROI :中断恢复位 0 = 中断对DOZEN 位没有影响 000 = FCY /1 0 = 处理器时钟/ 外设时钟频率比强制为1:1 bit 14-12 DOZE:处理器时钟分频比选择位 bit 11 DOZEN :打盹模式使能位

bit 10-8 FRCDIV:内部快速RC 振荡器后分频比位

000 = FRC 被1 分频(默认)

由公式 可知

bit 7-6 PLLPOST:PLL VCO 输出分频比选择位(也表示为“N2”,PLL 后分频比) 01 = 输出/4 (默认) bit 5 未实现:读为0 bit 4-0 PLLPRE:PLL 相位检测器输入分频比位(也表示为“N1”,PLL 预分频比) 1000=输入/10

FOSC=8*(162/(10*4))=32.4MHz

由此可知FCY=FOSC/2=16.2MIPS LATA = 0xFF00;将发光二极管(d3-d10 / ra0-ra7)低驱动状态

TRISA = 0xFF00;集LED 引脚(d3-d10 / ra0-ra7)输出

home_clr();

调用函数lcd_cmd( 0x01 )

TRISD &= 0xFF00; 确保 RD0 - RD7 输出

DATA &= 0xFF00; 准备 RD0 - RD7

DATA |= cmd; lcd 的命令字符为0x01

RW = 0; 确保 RW 是 0

RS = 0;

E = 1; 切换线路E

Delay(Delay_5mS_Cnt); 延时5毫秒

puts_lcd( (char*) &mytext[0], sizeof(mytext) -1 ); LCD 第一行显示" xxxIC33F Demo ";

line_2();

puts_lcd( (char*) &mytext1[0], sizeof(mytext1) -1 ); LCD 第二行显示"Press S3 to cont"; 当然如果想要显示其他的信息,只要将之前定义的数组const char mytext[] = " xxxIC33F Demo ";const char mytext1[] = "Press S3 to cont"; 中的内容更改为想要的的即可。如将”xxxIC33F”改为“Hello World”,则将显示“Hello World”。注意不能改为中文,否则出现乱码,因为ASCII 表中没有中文。

while ( PORTDbits.RD6 )

当PORTDbits.RD6=1即当s3未按下的时候,程序在这里死循环,显示屏上只显示”press s3 to start”的欢迎语句。当s3按下,PORTDbits.RD6=0,跳出循环,执行下面的语句。

Init_Timer1();

在init_timer11中可找到函数定义:

void Init_Timer1( void )

{

int current_cpu_ipl; 声明临时变量存储CPU IPL

T1CON = 0;确保定时器1处于复位状态

IFS0bits.T1IF = 0;重置定时器1中断标志

IPC0bits.T1IP = 4;设置定时器1中断优先级为4

IEC0bits.T1IE = 1;启用定时器1中断

PR1 = 0x8000;设置定时器1周期寄存器

T1CONbits.TCS = 1; 选择外部定时器时钟

char a, b, c, *p;

a = 2;

b = 0x46;

c = 0x57;

p = (char *)&OSCCON;

以下程序使用32KHz 振荡器,低字节解锁顺序并使用LP 振荡器

asm volatile ("mov.b %1,[%0] \n" "mov.b %2,[%0] \n"

"mov.b %3,[%0] \n" : /* no outputs */ : "r"(p), "r"(b), "r"(c),

"r"(a));

以下程序执行解锁顺序后重新存储CPU IPL值

T1CONbits.TON = 1;启用定时器1和开始计数

#if SLEEP == 1 while ( TMR1

#endif 如果主循环将进入休眠模式,则在这里等待振荡器开始,

定时器开始计数

以上执行后禁用中断解锁序列 home_clr();

再次调用函数lcd_cmd( 0x01 );

void lcd_cmd( char cmd )

{

TRISD &= 0xFF00; 确保 RD0 - RD7 输出

DATA &= 0xFF00; 准备 RD0 - RD7

DATA |= cmd; lcd 的命令字符为0x01

RW = 0; 确保 RW 是 0

RS = 0;

E = 1; 切换线路E

Delay(Delay_5mS_Cnt); 延时5毫秒

}

puts_lcd( (char*) &time_msg[0], sizeof(time_msg) -1 );LCD 第一行显示"Time 00:00: 00 ";

line_2();

puts_lcd( (char*) &adc_msg1[0], sizeof(adc_msg1) -1 ); LCD第二行显示" RP5 = 0.00

Vdc "

Init_ADC();初始化ADC

程序接下来进入无限循环

while ( 1 )

{

if ( rtc_lcd_update )

{

hexdec( hours );

Update_LCD();

rtc_lcd_update = 0;

}

我认为程序的核心函数是以下函数

void Update_LCD( void )

{

hours LCD 行与列的光标位置设置如下 home_it();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

lcd_data(tens + 0x30);

(lcd data()函数定义如下

RW = 0; 确保RW 为0

RS = 1; 断言寄存器选择为1

DATA &= 0xFF00; 准备 RD0 - RD7

DATA |= data; LCD 的数据字节

E = 1;

Nop();汇编语言中的空语句,以占用时间

Nop();

Nop();

E = 0; 切换E 信号

RS = 0; 否定寄存器选择0

Delay_Us( Delay200uS_count ); 延时200us

Delay_Us( Delay200uS_count ); 延时200us )

lcd_data(ones + 0x30);

在lcd.c 文件中由控制LCD 信号寄存器引脚的宏定义可知RW 、RS 、E 等符号的意义:

#define RW LATDbits.LATD5 #define RS LATBbits.LATB15 #define E LATDbits.LATD4

由手册知定义RW 代表LATD 寄存器Bit5即LATD5

RW -> RD5 LATD寄存器控制LCD 灯RW 信号

RS -> RB15 LATD 寄存器控制LCD 灯RS 信号

E -> RD4 LATD 寄存器控制LCD 灯E 信号

#define RW_TRIS T RISDbits.TRISD5

#define RS_TRIS TRISBbits.TRISB15

#define E_TRIS TRISDbits.TRISD4

RW_TRIS->TRISD5

RS_TRIS -> TRISB15

E_TRIS -> TRISD4 #define DATA LATE

#define DATAPORT PORTE

#define TRISDATA TRISE

)

在lcd_data()中起到核心作用的延时函数定义如下:

void Delay( unsigned int delay_count )

{

temp_count = delay_count +1;

asm volatile("outer: dec _temp_count"); asm volatile("cp0 _temp_count"); asm volatile("bra z, done");

asm volatile("do #3200, inner" );

asm volatile("nop");

asm volatile("inner: nop"); asm volatile("bra outer");

asm volatile("done:"); }

void Delay_Us( unsigned int delayUs_count )

{ temp_count = delayUs_count +1; asm volatile("outer1: dec _temp_count");

asm volatile("cp0 _temp_count");

asm volatile("bra z, done1");

asm volatile("do #1500, inner1" );

asm volatile("nop");

asm volatile("inner1: nop");

asm volatile("bra outer1");

asm volatile("done1:");

}

这两段程序采用汇编语言编写,由于能力有限,没有深究。在头文件delay.h 中,定义FCY 为16000000,前述可知,FCY=16200000,经检查我没有发现我的问题所在,故我认为处处应定义FCY 为16200000。这个头文件分别定义了200us 、1ms 、2ms 、5ms 、15ms 、1s 。只需在lcd_data()、lcd_cmd()中改变调用的延时函数即可改变延时时间,如将lcd_cmd()中的Delay(Delay_5mS_Cnt);改为Delay(Delay_15mS_Cnt);即可延长三倍时间。故作类似更改就可以最终使LCD 上显示的时间变快或者变慢。

由hexdec.c 文件可知,tens 为hours 十位上的数,ones 为个位上的数

以下同理

minutes LCD行与列的光标位置设置如下

hexdec( minutes );将

cursor_right();

cursor_right();

lcd_data(tens + 0x30);

lcd_data(ones + 0x30);

seconds LCD行与列的光标位置设置如下

hexdec( seconds ); cursor_right();

cursor_right();

lcd_data(tens + 0x30);

lcd_data(ones + 0x30);

}

由isr_timer1.c知,当seconds 达到59时,再加一变为00,当minutes 达到59时,再加一变为00,当hours 达到23时,再加一变为00当IFS0bits.T1IF = 0时,重置Timer 1 中断。程序命令rtc_lcd_update = 1;以其为执行Update_LCD();的标志。同样,在程序isr_ADC.c中,定义了ADC 中断程序。

本程序未理解的部分:

1. 主程序中的if ( adc_lcd_update )

{

line_2();

advolt( temp1 );

cursor_right();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

lcd_data( adones );

cursor_right();

lcd_data( adtens );

lcd_data( adhunds );

adc_lcd_update = 0;

}

};

} 为什么实时时钟要用模数转换器呢,在实验中,仅观察到第一行时间的变化,第二行没有 变化,那么第二行"RP5 = 0.00 Vdc"提示的是什么信息?

2. 主程序是如何调用Timer1中断处理程序的,即

void __attribute__((__interrupt__)) _T1Interrupt( void )?

3.以上深色标注的部分,这些函数为什么要连续调用好几次?它们实现了怎样的功能。

4. 主程序中“tens + 0x30”、”ones + 0x30”,以及advolts.c 中”adones += 0x30;adtens += 0x30;adhunds += 0x30;adthous += 0x30;”等,据查这是汇编语言的知识,其目的是是Explorer 16 上LCD 显示数字,不过这需要了解LCD 的手册,故我没有再做深究,只知道在这里起了显示数字的作用。

希望能在今后更深入的学习中弄清楚未解决的问题。

五、课程感悟

通过这一阶段的学习,终于打开了Microchip 的大门。大一时只是在硬件上的连接,现在终于可以揭开现象去看本质了。踏进程序的大门地时候,瞬间被其严密的逻辑、精巧的结构所吸引。作为一个平台,Micorichip 有着无限的可能,我很期待在自己能在这方面成为一名巧匠,去开发自己的作品,雕琢出自己的璞玉。所以参考书、论坛交流、自主尝试是必不可少的。

在学习的过程中遇到的困难数不胜数,有时仅仅一句语言,就不仅要牵扯到宏定义,条件编译等抽象的软件知识,还要牵扯到寄存器,配置位,DMA 等硬件知识,以及软硬之间的联系,失之毫厘便谬以千里。如此庞大的知识体系,为数几周的学习仅仅只能掌握九牛一毛的知识,本文中也必定有诸多过失。但我已经很努力在学习Microchip 了,并且兴趣越来越浓,实践的过程也是试错的过程,这些错误必将使我走得更远。

最后感谢刘教授耐心教导、清楚又不失风趣的讲解!下一学期我一定还要抢到这门如此有趣的实践课!

姓名:

学号:

学院:信息学院

专业:通信工程

指导老师:

时间:2015年12月22日

通信系统工程实践报告

一、创建一个新的工程

1. Project →Project Wizard…→点击下一步→选择芯片→选择Toolsuite

并确保没有打叉,设置储存位置→点击下一步→创建新的工程文件,选择一个文件夹,确定后即可在这个文件家里找到自己创建的工程→添加文件或稍后创建文件后添加→完成。

2.File →New(或点击快捷栏New File 图标) →无论是.h 还是.c 文件,编辑完成后保存,保存时即可选择保存为.h 还是.c →往文件夹中添加刚刚保存的.h 、.c 文件即可

二、串口通信实验:

1)步骤

1、将IDE 3、Explorer 16主板、音频子板、音频线、扩音器、电脑连接好,打开主板电源;

2、打开MPLAB ,点击File →Open Workspace →DTMF_710A_ASM_REV - OK →dtmf_gen.mcw

3、此时,界面将出现层层叠叠的许多窗口,现在,点击Window →Tile Horizontally使各窗口水平排列或点击Window →Tile Vertically使各窗口垂直排列;

4、点击Programmer →Select Programmer→MPLAB ICD 3;

5、点击Project →Build All或点击快捷菜单栏中的Build All按钮,如果出现语言工具选择对话框,则一律选择上方的Use this;

6、点击Programmer →Program ,开始烧录程序;

7、打开串口调试助手,选择电脑此时的串口(打开设备管理器即可看到是哪一个COM 口;波特率选择19200;

8、在输入框中输入#*012~9字符,点击手动发送,则看到界面显示了输入的内容,主板上的显示频同样显示了输入的内容,同时听到拨号音。

9、将自动发送打钩,串口调试助手将自动循环发送输入的内容。减小自动发送周期,原本清晰连续的拨号音将变快,继续减小周期,将变成不断地噪音;

2)问题发现

1.Buil All 失败。

2. 通过实验发现,每次只能返回输入内容的前8位。

3. 在在自己的电脑上安装MPLAB 后打不开工作区。

3)问题解决

1. 对于Build All失败:点击Project →Select Language Tool Location→Microchip C30

Toolsuite 。

2. 对于只返回前8位:将串口调试助手的数据位由8位改至10位依然只返回前8位而不是前10位。再改为6位时,只返回前6位。由此可知,仅返回8位不仅和串口调试助手这款软件有关,还与实验程序有关,由于能力有限,我没有找到具体原因。

3. 对于打不开工作区文件,检查是否安装mplabc30-v3_31-windows-installer.exe,检查安装路径是否正确,检查工作区文件路径是否含有中文等或违规字符,经检查,问题出在我将工作区文件放在了一个中文名文件夹下,导致软件不能识别,修改后顺利打开。

三、 MPLAB 使用心得

1. 程序#Include 中modems.h 在file 窗口中未找到,这时可以在文件夹中搜索

2. 修改字体、字形、大小:Eidt →Properties... →Text →Select Font →在这个窗口中,即可修

改字体等参数,选择合适的字大小能方便阅读程序。

其实Eidt →Properties... 有更多功能,现例举如下:

3、在C File Types选项卡中,选中Line number,可以显示代码行序号,方便查看;

4、在C File Types选项卡中,取消Double click toggles breakpoint选项,可以取消双击鼠标设置断点,代替为双击选中选取单词,再次双击选取整行;

5、在C File Types选项卡中,选中Enable Code Floding选项,可以实现代码折叠功能;

6、在Tools tips 选项卡中,选中AutoComplete 下面的几个选项,可以在输入源代码的时候自动提示函数集结构体。

7、选中use tabedd window,实现可使打开地多个源文件,显示在一个标签栏上, 方便源文件切换。

8、Window 中Tile Horizontally/Vertically可以使窗口水平/垂直排列,方便浏览。效果如下:

四、dsPIC33F Demo for Explorer 16 Board程序理解

总体理解:程序始终在执行hours 、minutes 、seconds 的加法工作,由hexdec.c 程序提取出时分秒的十位数和个位数,再由一些汇编语言结合LATD 、TRISA 等寄存器使LCD 显示数字。本程序选择了带PLL 的在XT 晶振模式下的主振荡器,即使用了内置8MHz 的FRC 震荡器,分频后产生的FOSC 为32.4MHz 。由此获得了200us 、1ms 、2ms 、5ms 、15ms 以及1s 的延时。通过延时使得时分秒间隔各自所需延时加一,提取了十位数和个位数后再显示到了LCD 屏上。于是实现了实时时钟功能。

以下为详细程序理解(粗体为源程序,其余为我的理解):

_FOSCSEL(FNOSC_PRIPLL);

_FOSC(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMD_XT);

_FWDT(FWDTEN_OFF);

在p33FJ256GP710A.h 中可查到如下定义:

#define FNOSC_PRIPLL 0xFFFB

转化为2进制:[**************]1,查手册知选用带PLL 的主(XT 、HS 或EC )振荡器

所以FNOSC_PRIPLL为带PLL 的主(XT 、HS 或EC )振荡器

#define FCKSM_CSDCMD 0xFFBF

转化为二进制:[**************],查手册知:FCKSM_CSDCMD为禁止时钟切换,禁止故障保护时钟监视器

#define OSCIOFNC_OFF 0xFFFF

转化为二进制:[**************]1查手册知OSCIOFNC_OFF表示 SC2 为时钟输出 #define POSCMD_XT 0xFFFD

转化为二进制:[**************]1查手册知POSCMD_XT为XT 晶振模式

#define FWDTEN_OFF 0xFF7F

转化为二进制:[**************]1查手册知FWDTEN_OFF即为通过用户软件使能/ 禁止看门狗定时器(可通过清零RCON 寄存器中的SWDTEN 位来禁止LPRC )

于是这三条语句实现的功能是:选用带PLL 的主(XT 、HS 或EC )振荡器,禁止时钟切换,禁止故障保护时钟监视器,SC2 为时钟输出,XT 晶振模式,通过用户软件使能/ 禁止看门狗定时器(可通过清零RCON 寄存器中的SWDTEN 位来禁止LPRC )

PLLFBD = 0x00A0;//给PLL 寄存器写入10100000

CLKDIV = 0x0048;//给ClDDIV 寄存器写入1001000

查手册中PLLFBD 寄存器表以及CLKDIV 表可知:

PLLFBD(PLL 反馈分频比寄存器) = 0x00A0; //10100000 162

bit 15-9 未实现:读为0

bit 8-0 PLLDIV:PLL 反馈分频比位(也表示为“M ”,PLL 倍频比)

010100000=162;

CLKDIV(时钟分频比寄存器) = 0x0048;//1001000

bit 15 ROI :中断恢复位 0 = 中断对DOZEN 位没有影响 000 = FCY /1 0 = 处理器时钟/ 外设时钟频率比强制为1:1 bit 14-12 DOZE:处理器时钟分频比选择位 bit 11 DOZEN :打盹模式使能位

bit 10-8 FRCDIV:内部快速RC 振荡器后分频比位

000 = FRC 被1 分频(默认)

由公式 可知

bit 7-6 PLLPOST:PLL VCO 输出分频比选择位(也表示为“N2”,PLL 后分频比) 01 = 输出/4 (默认) bit 5 未实现:读为0 bit 4-0 PLLPRE:PLL 相位检测器输入分频比位(也表示为“N1”,PLL 预分频比) 1000=输入/10

FOSC=8*(162/(10*4))=32.4MHz

由此可知FCY=FOSC/2=16.2MIPS LATA = 0xFF00;将发光二极管(d3-d10 / ra0-ra7)低驱动状态

TRISA = 0xFF00;集LED 引脚(d3-d10 / ra0-ra7)输出

home_clr();

调用函数lcd_cmd( 0x01 )

TRISD &= 0xFF00; 确保 RD0 - RD7 输出

DATA &= 0xFF00; 准备 RD0 - RD7

DATA |= cmd; lcd 的命令字符为0x01

RW = 0; 确保 RW 是 0

RS = 0;

E = 1; 切换线路E

Delay(Delay_5mS_Cnt); 延时5毫秒

puts_lcd( (char*) &mytext[0], sizeof(mytext) -1 ); LCD 第一行显示" xxxIC33F Demo ";

line_2();

puts_lcd( (char*) &mytext1[0], sizeof(mytext1) -1 ); LCD 第二行显示"Press S3 to cont"; 当然如果想要显示其他的信息,只要将之前定义的数组const char mytext[] = " xxxIC33F Demo ";const char mytext1[] = "Press S3 to cont"; 中的内容更改为想要的的即可。如将”xxxIC33F”改为“Hello World”,则将显示“Hello World”。注意不能改为中文,否则出现乱码,因为ASCII 表中没有中文。

while ( PORTDbits.RD6 )

当PORTDbits.RD6=1即当s3未按下的时候,程序在这里死循环,显示屏上只显示”press s3 to start”的欢迎语句。当s3按下,PORTDbits.RD6=0,跳出循环,执行下面的语句。

Init_Timer1();

在init_timer11中可找到函数定义:

void Init_Timer1( void )

{

int current_cpu_ipl; 声明临时变量存储CPU IPL

T1CON = 0;确保定时器1处于复位状态

IFS0bits.T1IF = 0;重置定时器1中断标志

IPC0bits.T1IP = 4;设置定时器1中断优先级为4

IEC0bits.T1IE = 1;启用定时器1中断

PR1 = 0x8000;设置定时器1周期寄存器

T1CONbits.TCS = 1; 选择外部定时器时钟

char a, b, c, *p;

a = 2;

b = 0x46;

c = 0x57;

p = (char *)&OSCCON;

以下程序使用32KHz 振荡器,低字节解锁顺序并使用LP 振荡器

asm volatile ("mov.b %1,[%0] \n" "mov.b %2,[%0] \n"

"mov.b %3,[%0] \n" : /* no outputs */ : "r"(p), "r"(b), "r"(c),

"r"(a));

以下程序执行解锁顺序后重新存储CPU IPL值

T1CONbits.TON = 1;启用定时器1和开始计数

#if SLEEP == 1 while ( TMR1

#endif 如果主循环将进入休眠模式,则在这里等待振荡器开始,

定时器开始计数

以上执行后禁用中断解锁序列 home_clr();

再次调用函数lcd_cmd( 0x01 );

void lcd_cmd( char cmd )

{

TRISD &= 0xFF00; 确保 RD0 - RD7 输出

DATA &= 0xFF00; 准备 RD0 - RD7

DATA |= cmd; lcd 的命令字符为0x01

RW = 0; 确保 RW 是 0

RS = 0;

E = 1; 切换线路E

Delay(Delay_5mS_Cnt); 延时5毫秒

}

puts_lcd( (char*) &time_msg[0], sizeof(time_msg) -1 );LCD 第一行显示"Time 00:00: 00 ";

line_2();

puts_lcd( (char*) &adc_msg1[0], sizeof(adc_msg1) -1 ); LCD第二行显示" RP5 = 0.00

Vdc "

Init_ADC();初始化ADC

程序接下来进入无限循环

while ( 1 )

{

if ( rtc_lcd_update )

{

hexdec( hours );

Update_LCD();

rtc_lcd_update = 0;

}

我认为程序的核心函数是以下函数

void Update_LCD( void )

{

hours LCD 行与列的光标位置设置如下 home_it();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

lcd_data(tens + 0x30);

(lcd data()函数定义如下

RW = 0; 确保RW 为0

RS = 1; 断言寄存器选择为1

DATA &= 0xFF00; 准备 RD0 - RD7

DATA |= data; LCD 的数据字节

E = 1;

Nop();汇编语言中的空语句,以占用时间

Nop();

Nop();

E = 0; 切换E 信号

RS = 0; 否定寄存器选择0

Delay_Us( Delay200uS_count ); 延时200us

Delay_Us( Delay200uS_count ); 延时200us )

lcd_data(ones + 0x30);

在lcd.c 文件中由控制LCD 信号寄存器引脚的宏定义可知RW 、RS 、E 等符号的意义:

#define RW LATDbits.LATD5 #define RS LATBbits.LATB15 #define E LATDbits.LATD4

由手册知定义RW 代表LATD 寄存器Bit5即LATD5

RW -> RD5 LATD寄存器控制LCD 灯RW 信号

RS -> RB15 LATD 寄存器控制LCD 灯RS 信号

E -> RD4 LATD 寄存器控制LCD 灯E 信号

#define RW_TRIS T RISDbits.TRISD5

#define RS_TRIS TRISBbits.TRISB15

#define E_TRIS TRISDbits.TRISD4

RW_TRIS->TRISD5

RS_TRIS -> TRISB15

E_TRIS -> TRISD4 #define DATA LATE

#define DATAPORT PORTE

#define TRISDATA TRISE

)

在lcd_data()中起到核心作用的延时函数定义如下:

void Delay( unsigned int delay_count )

{

temp_count = delay_count +1;

asm volatile("outer: dec _temp_count"); asm volatile("cp0 _temp_count"); asm volatile("bra z, done");

asm volatile("do #3200, inner" );

asm volatile("nop");

asm volatile("inner: nop"); asm volatile("bra outer");

asm volatile("done:"); }

void Delay_Us( unsigned int delayUs_count )

{ temp_count = delayUs_count +1; asm volatile("outer1: dec _temp_count");

asm volatile("cp0 _temp_count");

asm volatile("bra z, done1");

asm volatile("do #1500, inner1" );

asm volatile("nop");

asm volatile("inner1: nop");

asm volatile("bra outer1");

asm volatile("done1:");

}

这两段程序采用汇编语言编写,由于能力有限,没有深究。在头文件delay.h 中,定义FCY 为16000000,前述可知,FCY=16200000,经检查我没有发现我的问题所在,故我认为处处应定义FCY 为16200000。这个头文件分别定义了200us 、1ms 、2ms 、5ms 、15ms 、1s 。只需在lcd_data()、lcd_cmd()中改变调用的延时函数即可改变延时时间,如将lcd_cmd()中的Delay(Delay_5mS_Cnt);改为Delay(Delay_15mS_Cnt);即可延长三倍时间。故作类似更改就可以最终使LCD 上显示的时间变快或者变慢。

由hexdec.c 文件可知,tens 为hours 十位上的数,ones 为个位上的数

以下同理

minutes LCD行与列的光标位置设置如下

hexdec( minutes );将

cursor_right();

cursor_right();

lcd_data(tens + 0x30);

lcd_data(ones + 0x30);

seconds LCD行与列的光标位置设置如下

hexdec( seconds ); cursor_right();

cursor_right();

lcd_data(tens + 0x30);

lcd_data(ones + 0x30);

}

由isr_timer1.c知,当seconds 达到59时,再加一变为00,当minutes 达到59时,再加一变为00,当hours 达到23时,再加一变为00当IFS0bits.T1IF = 0时,重置Timer 1 中断。程序命令rtc_lcd_update = 1;以其为执行Update_LCD();的标志。同样,在程序isr_ADC.c中,定义了ADC 中断程序。

本程序未理解的部分:

1. 主程序中的if ( adc_lcd_update )

{

line_2();

advolt( temp1 );

cursor_right();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

cursor_right();

lcd_data( adones );

cursor_right();

lcd_data( adtens );

lcd_data( adhunds );

adc_lcd_update = 0;

}

};

} 为什么实时时钟要用模数转换器呢,在实验中,仅观察到第一行时间的变化,第二行没有 变化,那么第二行"RP5 = 0.00 Vdc"提示的是什么信息?

2. 主程序是如何调用Timer1中断处理程序的,即

void __attribute__((__interrupt__)) _T1Interrupt( void )?

3.以上深色标注的部分,这些函数为什么要连续调用好几次?它们实现了怎样的功能。

4. 主程序中“tens + 0x30”、”ones + 0x30”,以及advolts.c 中”adones += 0x30;adtens += 0x30;adhunds += 0x30;adthous += 0x30;”等,据查这是汇编语言的知识,其目的是是Explorer 16 上LCD 显示数字,不过这需要了解LCD 的手册,故我没有再做深究,只知道在这里起了显示数字的作用。

希望能在今后更深入的学习中弄清楚未解决的问题。

五、课程感悟

通过这一阶段的学习,终于打开了Microchip 的大门。大一时只是在硬件上的连接,现在终于可以揭开现象去看本质了。踏进程序的大门地时候,瞬间被其严密的逻辑、精巧的结构所吸引。作为一个平台,Micorichip 有着无限的可能,我很期待在自己能在这方面成为一名巧匠,去开发自己的作品,雕琢出自己的璞玉。所以参考书、论坛交流、自主尝试是必不可少的。

在学习的过程中遇到的困难数不胜数,有时仅仅一句语言,就不仅要牵扯到宏定义,条件编译等抽象的软件知识,还要牵扯到寄存器,配置位,DMA 等硬件知识,以及软硬之间的联系,失之毫厘便谬以千里。如此庞大的知识体系,为数几周的学习仅仅只能掌握九牛一毛的知识,本文中也必定有诸多过失。但我已经很努力在学习Microchip 了,并且兴趣越来越浓,实践的过程也是试错的过程,这些错误必将使我走得更远。

最后感谢刘教授耐心教导、清楚又不失风趣的讲解!下一学期我一定还要抢到这门如此有趣的实践课!


相关内容

  • 电子信息专业认识实习报告
  • 实 习 报 告 实习名称 专 业 认 识 实 习 专业班级 电子1142 姓 名 学 号 成 绩 评 定 电气与信息工程学院 二0一二年十月 实习纪律要求和成绩考核办法 实习纪律要求和成绩考核办法 1.实习过程必须听从教师和现场工作人员指导,严格遵守安全操作规程.不准违规操作,未经现场工作人员允许不 ...

  • 实践报告-移动
  • 实践报告 南京邮电大学 通信与信息工程学院 通信工程专业 年级:大二 班级:B080212 学号:B08021220 姓名:吴晓春 实践单位: 实践时间:2010年 7月20日至 8月2日 共14天 通过近两周的学习,我们从感性上学到了很多东西,也对我们将来的学习和研究方向的确定产生了深远的影响.通 ...

  • 通信建设工程实习报告
  • 通信建设工程实习报告 一.实习目的或研究目的 1.通过本次实习使我能够从理论回到到实践,更好的实现理论和实践的结合,为以后的工作和学习奠定初步的知识. 2.通过本次实习使我能够亲身感受到由一个学生转变到一个职业人的过程. 3.本次实习对我完成毕业设计和实习报告起到很重要的作用. 二.实习内容 201 ...

  • 网上书店 通信网络综合实践报告书
  • 安徽农业大学 综合性(设计性)实践报告书实践课题:班 级:姓 学 号:小组成员:指导教师: 通信网络综合实践 08通信一班 孙超 陶顺 唐成骏 刘波 2011年10月20日 通信网络综合实践报告书 08通信一班 08196039 杨韬 一.实践课题名称: 基础部分:网上书店 二.实践目的: (1)综 ...

  • 网络通信公司实习报告
  • 学生姓名:李xx 实习单位:co-exceed 实习时间:2012.12.03-2012.12.07 本人为中北大学信息商务学院08级电子信息工程专业三班的实习生李xx,从2012年12月3日至12月7日在北京协力超越科技公司进行了为期一周的实习活动.下面的内容就是有关于此次实习的心得总结. 此次实 ...

  • 通信工程学院暑假社会调查实践活动方案
  • 一、活动背景 1.中共中央、国务院16号文件中明确提出“社会实践是大学生思想政治教育的重要环节,对于促进大学生了解社会、了解国情,增长才干、奉献社会,锻炼毅力、培养品格,增强社会责任感具有不可替代的作用”。开展“志愿服务进基层”社会调查实践活动,引导大学生走出校门,到基层去,了解社情民意,主动投身和 ...

  • 光纤通信实践实验报告
  • 光纤通信课程实践 项目设计文档 题目光纤通信实践 学院物电学院专业 指导教师通信工程李理敏学生姓名赵煜华.石潇颖 2014年6月19 日 实验一光功率测试和模拟光发送实验时间2014 年6月17日同组者姓名赵煜华.石潇颖 1.实验目的 1.了解半导体光源的特性. 2.掌握光源P(平均发送光功率)-I ...

  • 电子信息工程专业生产实习报告
  • 电子信息工程专业生产实习报告 一、生产实习的目的 生产实习是电子信息工程专业以及其他任何专业十分重要的实践性教学环节,是培养学生实际动手能力和分析问题解决问题能力、理论与实践相结合的基本训练,同时也是学生毕业设计选题及设计工作原始资料的来源,为学生进行毕业设计打下扎实基础。认真抓好生产实习的教学工作 ...

  • 通信工程与概预算实训报告
  • 绵阳职业技术学院 实 训 报 告 第 至 学年第 学期 实训名称: 专业班级: 实训周次: 指导教师: 小组成员: 绵阳职业技术学院信息工程系 年 月 日 前 言 通信工程概预算是一门实践性很强的课程,我们从高等职业技术教育的要求出发,对该课程的实践教学进行了卓有成就的改革.实践教学环节的构成紧紧围 ...

  • 关于大学生电气自动化专业的实习报告
  • 1公司简介 珠江电信设备制造有限公司是专业生产高频开关电源及配套设备的高新技术企业,是目前中国最具实力的通信电源厂家之一.多年来,珠江公司专注于prtem高频开关电源及配套产品的自主研发.具备了较强的技术研发能力,成为了<通信用离网型风光互补系统标准>,<通信用太阳能供电系统> ...