您好,欢迎来到尚佳旅游分享网。
搜索
您的当前位置:首页PIC单片机课程设计:信号发生器

PIC单片机课程设计:信号发生器

来源:尚佳旅游分享网


福州大学

PIC课程设计》 信号发生器

学生姓名: XXXXXXXXXX 学 号: ******XXXX 专业班级: 电气学院2011级XX班 指导教师: XXXXXXXXX

二○一四 年 6 月 27 日

《哈哈,福大的学弟学妹们有福了。

目录

1、概述···································1 2、课程设计内容···························1 2.1、整体方案·····························1 2.2、硬件设计·····························2 2.3、软件设计·····························4 3、仿真结果·······························7 4、设计体会·······························11

1、概述

信号发生器是一种常用的信号源,广泛应用于电子电路、自动控制系统和教学实验等领域。目前使用的信号发生器大部分是函数信号发生器,且特殊波形发生器的价格昂贵。本设计采用PIC16F887单片机作为逻辑控制单元,利用MCP4821芯片转换单片机发出的数据,经过放大器放大产生正弦波、三角波、锯齿波和方波信号。通过外部按键切换波形,通过电位计经过AD转化控制信号周期大小。本设计利用液晶显示芯片1602作为显示单元,显示波形的类型和波形的周期。

信号发生器在显示生活中也起到很重要的作用,是电子技术领域的一种常用设备,长期以来都是由模拟电路构成的。这类仪器作为信号源,在高频范围内其频率稳定度高,可调性好。然而,在科学研究和生产实践中,如工业过程控制、生物医学等领域,通常需要用低频信号源。由模拟电路生成低频信号性能不能令人满意,而且用于低频其RC很大。大电阻、大电容在制造上有困难,参数准确度难以保证,同时体积大、漏电损耗显著。利用单片机用程序设计方法产生波形,其频率底限几乎无限度、稳定度好,频率幅值可以由电位计调整。

本设计实现的功能为:1、装置能生成正弦波、三角波、锯齿波、方波,通过波形切换按键进行切换。2、装置波形周期能通过电位计调节。3、生成波形设有两档,以满足更高周期(更低频率)的要求。

2、课程设计内容

2.1、整体方案

本设计采用PIC16F887单片机作为逻辑控制单元,通过MCP4821芯片转换单片机发出的数据,经过放大器放大产生正弦波、三角波、锯齿波和方波信号。通过电位计经过AD转化控制信号周期大小,通过外部按键切换波形。利用液晶显示芯片1602作为显示单元,显示波形的类型和波形的周期。整体框图如下图(图一)所示。

1

LCD1602显示模块PIC16F887单片机外部按键电位计DA转换模块MCP8421芯片图一:整体框图

放大器输出TL082CP 2.2、硬件设计

这次课设所用到的硬件模块有PIC16F887单片机芯片、LCD1602液晶显示芯

片、MCP8421芯片、TL082CP放大器、按键和电位计。硬件电路图如下图(图二所示)

图二:整体硬件图

2

(1)单片机模块:PIC16F877

本次课程设计所用的单片机为PIC16F877是16F877的升级版,主要参数与

877A类似,但使用更为灵活、有的参数更加细化(如RB口的使用),而价格比877A更低。887引脚与877A兼容,但增加了一些功能。 (2)显示模块:LCD1602

1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。 采用4位数据线接线方式,RD口的低四位和LCD的高4位连接,节省单片机的I/O口。液晶显示器用来显示时间,星期和温度,首先要进行显示时间定位,即写入命令。然后进行显示数据输入,即定初数据。VEE和VSS都拉低,VDD拉高电平。RS为0时,写命令,为1时写数据;R/W为1时表示读,0时表示写;E数据使能端,下降沿送入有效。RD0~RD3,数据输入端,使用液晶显示器端口的高4位。 RD7用于背光显示(RD7=1),RV1用于调整背光亮度,上电后要延时15ms 后,才能进行初始化。硬件连接图如下图(图三) 图三:LCD1602硬件连接图 3

(3)DA转换模块:MCP8421芯片

Microchip Technology lnc.的MCP482X器件为2.7V-5.5V、低功耗、地DNL

的12位数模转换器,具有内部带隙电压基准,可选2x缓冲器输出和串行外设接口(SPI)。

本设计通过SPI通讯与MCP8421芯片通讯,将数据量转化成模拟量。

(4)放大器模块:TL082CP芯片

TL082CP芯片是双列8引脚封装。结型场效应管高阻输入,工作电压=+/-18V,

静态电流=1.4mA,输入偏置电流=30PA,转换速率=16V/us,功耗=680mW,增益带宽=3MHz,输入失调电压=2-5mV,工作温度=-55-125°C,电压反馈型。

本设计DA转换后,通过TL082CP芯片,经过一电压跟随器和一级放大输出

所要的波形。

DA转换模块和放大器模块硬件连接图如下图(图四)

图四:DA转换及放大器硬件连接图

2.3、软件设计

本设计以PIC16F887单片机为主控器,有数模转换电路,运算放大器等组成

低频信号发生器。

主要思想为:通过TMR2定时器定时的通过SPI通讯向MCP8421芯片输出数

据进行DA转换,在主循环中不断的进行AD采样,和向LCD1602显示模块输入数据显示所要显示所生成的波形和周期。

主程序及中断的流程图如下图(图五)。

4

TMR2中断RB口中断Wave=1主程序开始延时10毫秒YES程序初始化输出正弦波NO的点RB0=1YESAD转换Wave=2YESNOWave=4YESWave=1NOLCD显示输出三角波NO的点Wave++Wave=3YES输出锯齿波NO的点NOWave=4YES输出方波的NO点RB1=1YESK=1YESK=0T2CON=0b00000100NOK=1T2CON=0b00000101延时30毫秒TMR2IF=0中断结束中断结束

图五:程序及中断流程图

主函数不断的进行AD转换以及LCD显示,将AD转换值赋给PR2以调节输出

波形周期,LCD显示输出为何波形,周期为多少。

通过定时器二TMR2中断定时输出波形的点,调整定时器的定时时间即可改

变输出波形的周期。RB口按键中断用于切换波形和调档。调档即调整定时器二的预分频比。

5

各子程序流程图如图下图(图六)。

AD转换开始DA转换开始LCD初始化LCD写数据AD转换DA转换初始化初始化功能设置入口采样延时CS=0显示开关控制写入D3-D0分两次SPIGO=1传数据给光标、画面位移设置延时MCP8421GO=1LDAC=0清屏设置高四位与第四位交换等待LDAC=1返回写入D7-D4CS=1延时ADIF=0返回返回转化结果存入AD_RESULTPR2=AD_RESULT返回图六:个子程序流程图

6

LCD显示LCD初始化选通LCD1602写入数据显示初始地址写入显示数据的代码执行显示返回显示计算周期TBCD码转换LCD显示返回

3、仿真结果

如下图为方正结果:

方波波形图

锯齿波波形图

7

三角波波形图

正弦波波形图

8

现在以正弦波为例,显示周期调整和换挡的功能。分别为高档和低档时的波形:

高档时的正弦波波形

低档时的正弦波波形

9

电位计调得较大

电位计调得较小

10

4、设计体会

课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程.随着科学技术发展的日新日异,单片机已经成为当今计算机应用中空前活跃的领域,在生活中可以说得是无处不在。因此作为二十一世纪的大学来说掌握单片机的开发技术是十分重要的。

本次设计的一个非常的的收获是意识到结构框架的对整个设计的重要性,设

计时应该遵循“先整体后隔离”和“循序渐进”的思路。

“先整体后隔离”:先根据要实现的功能确定整体框架,明确那些要放在主函数中?那些要放在中断中?需要用到哪些模块?先写好程序流程图,再深入解决每个小模块,子程序。

“循序渐进”:程序不能一些子就完成,因此,可分模块完成,先让程序完成较为基本的功能,在逐一添加模块。这样一旦出问题就能尽快的确定问题出来哪里。

本次的设计遇到的很多的问题,通过问题的解决,我不断的提高自己检测问题和解决问题的能力,并从中收获颇多有所总结。以为对如何排查问题的总结:故障的排查可以从“空间”和“时间”上排查。“空间”上排查即为:把整个系统划分为几个模块,如软件模块,硬件模块,其中软硬件又可以因具体情况再加以细分,然后通过软件调试设置断点,和用万用表检查硬件模块来缩小范围,最终确定问题所在。“时间”上的排查即为:把要实现的结果在流程上划分为几个阶段,然后逐个排查运行到各个阶段是否与预期的情况一样,从而确定问题出来哪里。

11

程序如下:

#include __CONFIG(0x00F1); __CONFIG(0x3FFF);

#define uchar unsigned char #define uint unsigned int #define nn 100

/*-------DA转换相关宏定义------*/ #define SHDN RE2 #define CS RE1 #define LDAC RE0

/*-------LCD相关宏定义---------*/ #define LCD_RS RD4 #define LCD_RW RD5 #define LCD_E RD6 #define LCD_LED RD7

#define COM 0//定义命令为0 #define DATA 1//定义数据为1 /*-------SPI通讯相关宏定义-----*/ #define SPI_WRITE(A) \\ SSPBUF=A; \\ while(BF==0); \\ BUF=SSPBUF

/*-------全局变量设置----------*/

unsigned int X; //DA转换的变量数字量 unsigned int AD_RESULT; char BUF,N; char wave; //波形代号 char k; //档次,对应两个分频比。 bit K; //档次,对应两个分频比。 unsigned int T; //周期 char dis[16]=\"T= . ms \";

//正弦波表格,

const unsigned int SIN[100]={

2048,2111,2173,2235,2297,2357,2416,2474,2530,2584, 2636,2685,2733,2777,2819,2857,22,2924,2953,2978, 2999,3017,3030,3040,3046,3048,3046,3040,3030,3017, 2999,2978,2953,2924,22,2857,2819,2777,2733,2685, 2636,2584,2530,2474,2416,2357,2297,2235,2173,2111, 2048,1985,1923,1861,1799,1739,1680,1622,1566,1512,

12

1460,1411,1363,1319,1277,1239,1204,1172,1143,1118, 1097,1079,1066,1056,1050,1048,1050,1056,1066,1079, 1097,1118,1143,1172,1204,1239,1277,1319,1363,1411, 1460,1512,1566,1622,1680,1739,1799,1861,1923,1985}; //三角波表格,

const unsigned int triangular[100]={

2048,2088,2128,2168,2208,2248,2288,2328,2368,2408, 2448,2488,2528,2568,2608,28,2688,2728,2768,2808, 2848,2888,2928,2968,3008,3048,3008,2968,2928,2888, 2848,2808,2768,2728,2688,28,2608,2568,2528,2488, 2448,2408,2368,2328,2288,2248,2208,2168,2128,2088, 2048,2008,1968,1928,1888,1848,1808,1768,1728,1688, 18,1608,1568,1528,1488,1448,1408,1368,1328,1288, 1248,1208,1168,1128,1088,1048,1088,1128,1168,1208, 1248,1288,1328,1368,1408,1448,1488,1528,1568,1608, 18,1688,1728,1768,1808,1848,1888,1928,1968,2008}; //锯齿波表格,

const unsigned int sawtooth[100]={

1048,1068,1088,1108,1128,1148,1168,1188,1208,1228, 1248,1268,1288,1308,1328,1348,1368,1388,1408,1428, 1448,1468,1488,1508,1528,18,1568,1588,1608,1628, 18,1668,1688,1708,1728,1748,1768,1788,1808,1828, 1848,1868,1888,1908,1928,1948,1968,1988,2008,2028, 2048,2068,2088,2108,2128,2148,2168,2188,2208,2228, 2248,2268,2288,2308,2328,2348,2368,2388,2408,2428, 2448,2468,2488,2508,2528,28,2568,2588,2608,2628, 28,2668,2688,2708,2728,2748,2768,2788,2808,2828, 2848,2868,2888,2908,2928,9488,2968,2988,3008,3028}; const unsigned int square[100]={

1048,1048,1048,1048,1048,1048,1048,1048,1048,1048, 1048,1048,1048,1048,1048,1048,1048,1048,1048,1048, 1048,1048,1048,1048,1048,1048,1048,1048,1048,1048, 1048,1048,1048,1048,1048,1048,1048,1048,1048,1048, 1048,1048,1048,1048,1048,1048,1048,1048,1048,1048, 3048,3048,3048,3048,3048,3048,3048,3048,3048,3048, 3048,3048,3048,3048,3048,3048,3048,3048,3048,3048, 3048,3048,3048,3048,3048,3048,3048,3048,3048,3048, 3048,3048,3048,3048,3048,3048,3048,3048,3048,3048, 3048,3048,3048,3048,3048,3048,3048,3048,3048,3048}; //函数声明!

void DAC(uint x); //DA转换程序 void CSH(); //初始化 void display(uint R1,char R2); void ADC(char k);

13

void DELAY_INT(uint n); /*-------生成波形------------*/ void out_sin(); //输出正弦波 void out_triangular(); //输出三角波 void out_sawtooth(); //输出锯齿波 void out_square(); //输出方波 /*-------LCD相关函数---------*/ void LCD_CSH(void); void LCD_BUSY(void); uchar LCD_READ(void);

void LCD_WRITE(uchar R1,uchar FLAG); void LCD_WRITE_4(uchar R1,uchar FLAG); void DELAY_US(uchar n); void DELAY(uint n);

void LCD_WRITE_STR(uchar R1,uchar R2,const uchar *str);

void main(void) { CSH(); LCD_CSH(); wave=1; K=0; N=0; ADC(0); PR2=AD_RESULT>>2; while(1) { display(T,K); ADC(0); } }

//===========中断服务子程序。 void interrupt INT_ISR(void) { if(TMR2IF==1) { if(wave==1) out_sin(); if(wave==2) out_triangular(); if(wave==3) out_sawtooth(); if(wave==4)

14

//LCD显示

out_square(); } if(RBIF==1) { DELAY_INT(10); if(RB0==0) { if(wave++==4) wave=1; } if(RB1==0) { if(K==1) K=0; else K=1; if(K==0) T2CON=0b00000100; if(K==1) T2CON=0b00000101; } DELAY_INT(30); } RBIF=0; TMR2IF=0; TMR2=0; }

void display(uint R1,char R2) { char q=0,b=0,s=0,g=0; if(R2==0) {k=1;dis[11]='L';} if(R2==1) {k=4;dis[11]='H';} T=224+PR2*k; while(T>=1000) {T-=1000;q++;} while(T>=100) {T-=100;b++;} while(T>=10) {T-=10;s++;} g=T; dis[2]=q+'0';

//TMR2使能,预分频比,后分频比1:1 //TMR2使能,预分频比,后分频比1:4 15

dis[3]=b+'0'; dis[4]=s+'0'; dis[6]=g+'0'; if(wave==1) LCD_WRITE_STR(0,0,\"sine wave \"); if(wave==2) LCD_WRITE_STR(0,0,\"triangular wave \"); if(wave==3) LCD_WRITE_STR(0,0,\"sawtooth wave \"); if(wave==4) LCD_WRITE_STR(0,0,\"square wave \"); LCD_WRITE_STR(1,0,dis); }

//////DA转换 void DAC(uint x) { char i,j; x+=0x7000; //HSDN=1,参考电压缓冲,放大倍数GA=1 CS=0; //片选有效 i=x>>8; j=x; SPI_WRITE(i); //输出命令的高8位 SPI_WRITE(j); //输出命令的低8位 LDAC=0;NOP(); //DA输出有效 LDAC=1;NOP(); CS=1; }

void ADC(char k) { char i; ADCON0=0b01000001; ADCON1=0b10000010; ADCON0|=(k<<3); for(i=0;i<5;i++) NOP(); GO=1; while(GO==1); ADIF=0; AD_RESULT=0; AD_RESULT=ADRESH<<8; AD_RESULT|=ADRESL; //结果存在于AD_RESULT中 PR2=AD_RESULT>>2; }

/////初始化

16

void CSH() { ANSELH=0; //设B口为普通IO口 // ANSEL=0; //设RE口为普通I/O口s ANSEL=0b00000011; //设RA0和RA1口为模拟量输入 TRISA=0b00000011; //设RA0口为输入 TRISB=0b00001111; TRISC=0b00010000; //RC3输出(SCK),RC4输入(SDI),RC5输出(SDO) TRISD=0b00000000; //RD口为输出,显示LCD模块。 TRISE=0b11111000; //RE0-2为输出 //----AD转化设置-------// ADCON0=0b01000001; ADCON1=0b10001110; //----中断和T0设置-----// OPTION_REG=0b00001000; //允许上拉电阻,预分频给看门狗,即TMR0分频比1:1. WPUB=0b00001111; IOCB=0b00001111; //低四位电平变化中断允许 GIE=1;RBIE=1;RBIF=0;TMR0IE=0;T0IF=0; //----TMR2设置--------// //PR2=99; //按照计算,每20us中断一次 T2CON=0b00000100; TMR2IE=1; //允许TMR2中断 PEIE=1; GIE=1; //----SPI相关设置-----// SHDN=1; //RE2 NOP(); CS=1; //RE1 NOP(); LDAC=1; //RE0 SSPEN=1; //SPI串口使能 CKP=1; //空闲时钟为高电平 SSPM3=0; SSPM2=0; SSPM1=0; SSPM0=0; //SPI主控模式,时钟为Fosc/4 SMP=1; //在数据输出时间的末端采样输入数据 CKE=0; //在SCK上升沿传输数据 }

//////输出正弦波 void out_sin()

17

{ X=SIN[N++]; if (N>=nn) N=0; DAC(X); }

//////输出三角波 void out_triangular() { X=triangular[N++]; if (N>=nn) N=0; DAC(X); }

//////输出锯齿波 void out_sawtooth() { X=sawtooth[N++]; if(N>=nn) N=0; DAC(X); }

//////输出方波 void out_square() { X=square[N++]; if(N>=nn) N=0; DAC(X); }

//LCD模块初始化 void LCD_CSH(void) { LCD_LED=1; DELAY(20); //延时20ms LCD_WRITE_4(0b0011,COM); //发送控制序列 DELAY_US(10); //延时100us LCD_WRITE_4(0b0011,COM); //发送控制序列 DELAY_US(10); //延时100us LCD_WRITE_4(0b0011,COM); //发送控制序列 DELAY_US(10); //延时100us LCD_WRITE_4(0b0010,COM); //4位数据格式 LCD_BUSY(); //LCD忙检测

18

LCD_WRITE(0b00101000,COM); //4位数据格式,4行,5×7点阵 LCD_WRITE(0b00001100,COM); //D(d2)=1:打开显示,C(d1)=1:光标打开,B(d0)=1:光标不闪烁 LCD_WRITE(0b00000001,COM); //清除显示 DELAY(2); //延时2ms LCD_WRITE(0b00000110,COM); //输入模式,I/D(d1)=1:地址加1,S(d0)=1:显示移位关闭 }

//========读LCD状态 char LCD_READ(void) { char R1; TRISD|=0x0F; //LCD数据线为输入 LCD_RS=0; //寄存器选择 LCD_RW=1;NOP(); //读为1 LCD_E=1;NOP(); //使能 R1=0; //短延时 R1=PORTD&0x0F; LCD_E=0;NOP(); LCD_E=1;NOP(); //使能 R1=R1<<4; //读数据的高4位给R1高4位 R1|= PORTD&0x0F; //读PORTD的0-3位,R1的高4位不变 LCD_E=0;NOP(); //读数据结束 LCD_RW=0; TRISD&=0xF0; //LCD数据线为输出 return (R1); }

void LCD_WRITE(char R1,char FLAG) { char R2; LCD_BUSY(); R2=R1&0xF0; R2=R2>>4; LCD_WRITE_4(R2,FLAG); R2=R1&0x0F; LCD_WRITE_4(R2,FLAG); DELAY_US(10); }

void LCD_WRITE_4(char R1,char FLAG) { LCD_RW=0;NOP(); LCD_RS=FLAG;NOP(); PORTD&=0xF0;NOP(); LCD_E=1;NOP();

19

PORTD|=R1;NOP(); LCD_E=0;NOP(); LCD_RS=0;NOP(); PORTD&=0xF0; }

//========检测LCD是否忙 void LCD_BUSY(void) { unsigned char R1; while(1) { R1=LCD_READ(); //读寄存器 if ((R1 & 0x80)==0x00) //最高位为忙标志位 break; }; }

/*-------------------------------------- ;模块名称:LCD_WRITE_STR();

;功 能:LCD1602显示字符串函数, 在某个屏幕起始位置{R1(1-2),R2(0-15)}上显示一个字符串。 ;-------------------------------------*/

void LCD_WRITE_STR(uchar R1,uchar R2,const uchar *str) {

uchar address; if(R1==0)

address=0x80+R2; else

address=0xc0+R2; LCD_WRITE(address,0); while(*str!='\\0') {

LCD_WRITE(*str,1); str++; } }

//======延时(n)ms void DELAY(uint n) { uint j; uchar k; for (j=0;j0;k--) NOP(); }

//======延时(n×10)us void DELAY_US(uchar n) { uchar j; for (j=0;j20

{NOP();NOP();} }

void DELAY_INT(uint n) { uint j; uchar k; for (j=0;j0;k--) NOP(); }

21

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- shangjiatang.cn 版权所有 湘ICP备2022005869号-4

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务