pic18fxx8单片机通用同步异步收发器的接口电路和c源代码
PIC18F单片机(第一章)课件
国内单片机的应用现状
基本上以51内核为主 随着市场的细分和产品设计所需,PIC单片机 的应用范围和市场占有率也随之上升 近年来,针对PIC单片机的设计和应用,国内 也陆续出版了一些参考书籍(以北航为首)
1.1 PIC单片机的分类
16 bit MCU 24 bits dsPIC 16 bits Data Memory Width PIC18 Program Memory Width
PIC18F系列单片机的程序、数据 和堆栈三者各自采用互相独立的 地址空间
21-Bits
12-Bits
程 序 存 储 器
程序地址
数据地址
PIC 指令总线 18FXXXCPU
16-Bits
数据总线
数 据 存 储 器
8-Bits
2. 2MB的程序存储器
–
–
PC为21位宽,最大可寻址221= 2MB 000000H~1FFFFFH
–
寄存器间接寻址、立即数寻址、直接寻址和位寻址 PIC18FXX8单片机只有58条指令
指令数少
–
9. 带优先级的中断
– –
高优先级中断向量——000008H 低优先级中断向量——000018H
10. 8×8 单周期硬件乘法器
– –
提高了计算能力 减少乘法运算法则所需代码长度
二、外围功能模块特性
芯片内部含有10位ADC、内部EEPROM存储
器、比较输出、捕捉输入、PWM输出、I2C和
SPI接口、CAN接口(452没有)、USART、 Flash程序存储器读/写等强大功能。
三、内部结构
RA端口 RB端口 RC端口 RD端口 RE端口 并行从动 端口
电源 参考源
PIC_单片机软件异步串行口实现的C语言参源程序
#i nclude <pic.h> //PIC单片机通用头文件,实际型号为16F84__CONFIG(XT | PROTECT | PWRTEN | WDTEN);//程序中设定配置信息//===========================//定义软件UART发送/接收引脚//===========================#define RX_PIN RB0 //串行接收脚#define TX_PIN RB1 //串行发送脚//===========================//定义软件UART状态机控制字//===========================#define RS_IDLE 0 //空闲#define RS_DATA_BIT 1 //数据位#define RS_STOP_BIT 2 //停止位#define RS_STOP_END 3 //停止位结束//===========================//定义软件UART采样频率//===========================#define OSC_FREQ 4000 //单片机工作频率(单位:KHz)#define BAUDRATE 1200 //通讯波特率#define TMR0PRE 2 //TMR0预分频比1:2#define TMR0CONST 117 //256 - OSC_FREQ*1000/TMR0PRE/4/(BAUDRATE*3)//===================================================================//定义函数类型void UART_Out(void);void UART_In(void);//===================================================================//定义位变量bit rsTxBusy; //串行发送忙标志//定义串行发送的数据结构struct {unsigned char state; //发送状态机控制单元unsigned char sliceCount; //波特率控制unsigned char shiftBuff; //字节数据发送移位寄存器unsigned char shiftCount; //字节数据发送移位计数器} rsTx;//定义串行接收的数据结构struct {unsigned char state; //接收状态机控制单元unsigned char sliceCount; //波特率(采样点)控制unsigned char shiftBuff; //字节数据接收移位寄存器unsigned char shiftCount; //字节数据接收移位计数器unsigned char dataBuff[8]; //接收数据FIFO缓冲队列unsigned char putPtr, getPtr;//FIFO队列存放/读取指针} rsRx;//用于串行发送的变量定义unsigned char outBuff[10]; //发送队列unsigned char outPtr, //发送队列指针outTotal, //发送的字节总数chkSum; //发送的校验码//===================================================================== //主程序//===================================================================== void main(void){PORTA = 0;PORTB = 0;TRISB = 0b01; //输入输出定义OPTION = 0b10000000; //TMR0选择内部指令周期计数//TMR0预分频 1:2rsRx.state = RS_IDLE; //初始化接收状态rsTxBusy = 0; //发送空闲INTCON = 0b00100000; //T0IE使能GIE = 1; //打开中断while(1) { //程序主循环asm("clrwdt"); //清看门狗UART_In(); //接收串行数据UART_Out(); //发送串行数据}}//=====================================================================//查询在接收FIFO队列中是否有新数据到//然后解读数据//===================================================================== void UART_In(void){unsigned char data1;if (rsRx.putPtr==rsRx.getPtr)return; //如果读取和存放的指针相同,则队列为空data1 = rsRx.dataBuff[rsRx.getPtr]; //读取1个数据字节rsRx.getPtr++; //调整读取指针到下一位置rsRx.getPtr &= 0x07; //考虑环形队列回绕//此处为数据解读分析,略}//===================================================================== //软件UART发送数据//数据在outBuff中,outTotal为总字节数//===================================================================== void UART_Out(void){if (rsTxBusy==1)return; //正处于移位发送忙//可以发送新数据if (outTotal) { //如果有字节要发送rsTx.shiftBuff = outBuff[outPtr++]; //取字节到发送移位寄存器rsTxBusy = 1; //置发送忙标志,启动发送outTotal--; //字节计数器减1}}//=================================================================== //中断服务程序//=================================================================== void interrupt isr(void){//利用TMR0 定时中断实现全双工软件UARTif (T0IE && T0IF) {T0IF = 0; //清TMR0中断标志//实现串行接收 RX 状态机控制switch (rsRx.state) { //判当前接收状态case RS_IDLE://当前状态为"空闲", 唯一要做的就是判"起始位"出现if (RX_PIN==0) { //如果接收到低电平rsRx.sliceCount = 4; //准备4*Ts时间间隔rsRx.shiftCount = 8; //总共接收8位数据位//改变此数值可以实现任意位数的数据接收rsRx.state = RS_DATA_BIT; //切换到数据位接收状态}break;case RS_DATA_BIT://当前状态为"数据接收"if (--rsRx.sliceCount==0) { //等采样时间到rsRx.shiftBuff >>= 1; //接收移位寄存器右移1位if (RX_PIN) rsRx.shiftBuff|=0x80; //保存最新收到的数据位 rsRx.sliceCount = 3; //下次采样间隔为3*Tsif (--rsRx.shiftCount==0) { //已经收到8位数据位?//保存数据字节到FIFO缓冲队列rsRx.dataBuff[rsRx.putPtr] = rsRx.shiftBuff;//队列存放指针调整,最多8个字节缓冲rsRx.putPtr = (rsRx.putPtr+1) & 0x07;//转去下个状态,判停止位rsRx.state = RS_STOP_BIT;}}break;case RS_STOP_BIT://当前状态为停止位判别(此程序没有判别)if (--rsRx.sliceCount==0) { //等采样时间到//此处可以判RX_PIN是否为1rsRx.state = RS_IDLE; //复位接收过程}break;default://异常处理rsRx.state = RS_IDLE; //复位接收过程}//实现串行发送 TX 状态机控制switch (rsTx.state) { //判当前发送状态case RS_IDLE: //发送起始位if (rsTxBusy) { //如果发送启动TX_PIN = 0; //发出起始位低电平rsTx.sliceCount = 3; //持续时间3*TsrsTx.shiftCount = 8; //数据位数为8位rsTx.state = RS_DATA_BIT; //转去下一状态} else TX_PIN = 1; //如果没有数据发送则保证数据线为空闲 break;case RS_DATA_BIT: //发送8位数据位if (--rsTx.sliceCount==0) { //码元宽度定时到if (rsTx.shiftBuff & 0x01)//看数据位是0还是1TX_PIN = 1; //发送1elseTX_PIN = 0; //发送0rsTx.shiftBuff >>= 1; //准备下次数据位发送rsTx.sliceCount = 3; //数据位宽度为3*Tsif (--rsTx.shiftCount==0) {//8位数据位发送结束,转去发送停止位rsTx.state = RS_STOP_BIT;}}break;case RS_STOP_BIT: //发送1位停止位if (--rsTx.sliceCount==0) { //等数据位发送结束TX_PIN = 1; //发送停止位高电平rsTx.sliceCount = 9; //持续宽度9*Ts//额外考虑字节连续发送的时间间隔rsTx.state = RS_STOP_END; //转停止位宽度延时}break;case RS_STOP_END: //等待停止位时间宽度结束if (--rsTx.sliceCount==0) { //如果停止位结束时间到rsTxBusy = 0; //一个字节发送过程结束,清发送忙标志rsTx.state = RS_IDLE; //复位发送过程}break;default://异常处理rsTx.state = RS_IDLE; //复位发送过程}TMR0 += TMR0CONST; //重载TMR0,实现下次定时中断}}。
pic18f87k90单片机 读写Fram铁电MB85RC16 iic(i2c)方式 源代码示例
首页 我的主页 相册 广场
私信 模板 设置 退出
与时空的空间
2012-11-12 10:28
pic18f87k90单片机 读写 Fram 铁电 MB85RC16 iic(i2c)方式 源代码示例
/*////////////////////////////////////// 主模式初始化 //////////////////////////////////////*/ void Fram_iic_init() {
{ PIR1bits.SSP1IF=0; addh<<1; addh&=0x0e; addh+=0xa0;
SSP1CON2bits.SEN=1; while(!PIR1bits.SSP1IF); PIR1bits.SSP1IF=0;
SSP1BUF=addh; while(!PIR1bits.SSP1IF); PIR1bits.SSP1IF=0; while(SSP1CON2bits.ACKSTAT);
PIR1bits.SSP1IF=0;
temp_save=SSP1BUF;
SSP1CON2bits.ACKDT=1; SSP1CON2bits.ACKEN=1;
while(!PIR1bits.SSP1IF); PIR1bits.SSP1IF=0;
SSP1CON2bits.PEN=1;
while(!PIR1bits.SSP1IF); PIR1bits.SSP1IF=0;
SSPCON1=0X00; //SSP 模块 JINGZHI 使能
ODCON1=0X80;
TRISCbits.TRISC3 =1;
TRISCbits.TRISC4 =1;
PIC单片机的C语言使用
PIC单片机的C语言使用PIC单片机是一种常见的微控制器芯片,它具有高性能、低功耗和易操作的特点,可广泛应用于各种嵌入式系统开发中。
在PIC单片机的开发过程中,C语言是一种常用的编程语言,本文将介绍PIC单片机的C语言使用。
首先,我们需要了解PIC单片机的基本知识。
PIC单片机拥有多种系列和型号,每种型号都有自己的特点和功能。
在编程之前,我们需要选择合适的型号,并学习其相应的数据手册和用户指南,熟悉芯片的引脚分配、寄存器结构和功能等信息。
在PIC单片机的C语言开发中,我们可以利用一些常用的开发环境和编译器来进行开发。
例如,MPLABX是一种常用的IDE集成开发环境,它可以为PIC单片机提供强大的开发和调试功能。
另外,XC8是一种常用的C编译器,可以将C语言源代码编译成PIC单片机可执行的指令。
在编写PIC单片机的C语言程序时,我们需要熟悉一些基本的语法和语句。
例如,条件语句(if-else语句)可以用于控制程序的流程,循环语句(for循环和while循环)可以用于重复执行段代码,函数可以将一系列的代码封装成一个可复用的模块等等。
此外,C语言还提供了丰富的数据类型和操作符,可以方便地进行变量声明和运算操作。
在PIC单片机的C语言开发中,我们经常需要使用寄存器来配置芯片的各种功能和特性。
寄存器是PIC单片机内部的一种特殊的内存单元,可以用于存储控制和配置信息。
通过访问这些寄存器,我们可以配置IO口、定时器、中断、串口通信等各种功能,并与外部设备进行数据交换。
在C语言中,我们可以使用关键字“volatile”来声明一个寄存器变量,以确保编译器不会对其进行优化。
除了基本的语法和寄存器操作之外,PIC单片机的C语言开发还需要掌握一些常用的库函数和编程技巧。
例如,stdio.h库提供了一系列常用的输入输出函数,可以方便地进行串口通信和打印调试信息。
另外,math.h库提供了一些常用的数学函数,可以进行浮点数运算和数值计算。
PIC18系列单片机原理及实践【精选】
2019/9/11
大连理工大学 电工电子实验中心 陈育斌
18
1.5 PIC微控制器的数据RAM和E2PROM
RAM和E2PROM都是用来存储数据的。其中:
1. RAM用于存储程序的“变量”,如系统采集的输入数据、 处理运算的中间结果或者是程序的最终数据等。
大连理工大学 电工电子实验中心 陈育斌
3
第一章 PIC微控制器的历史和特征
1989年Microchip公司开发了一种8位的微控制器: PIC(Peripheral Interface Controler ——— 外围接口控制器);
将少量的RAM、ROM、一个定时器和一些I/O端口全 部集成在一个8脚的芯片上;
2. 将芯片内部所包含的ADC、定时器、同步/异步收发器、 E2PROM、看门狗WDT、I2C总线、CAN总线接口等统 称为“外围模块”。外围模块有两个特征:
①都是由对应的SFR进行初始化控制;
②在PIC18XXX系列中,不同的型号其配置各不相同。
2019/9/11
大连理工大学 电工电子实验中心 陈育斌
RAM的大小影响着CPU处理数据的空间。一个大容量的 RAM还可以使高级语言运行更为流畅。
特点:存储速度快(与指令运行的速度同步)、掉电后 数据丢失。
2. E2PROM用于存储 “重要而不需经常修改的数据”。一 般是结果数据,如:水表的流量、汽车的行驶里程、远 端采集的遥感数据等。
特点:掉电后数据不丢失、存储数据速度慢(ms级)。
1. 16FXXX:具有丰富的内部模块、完整的指令系统和良 好的向下兼容性。适合初学入门的系列;
PIC18 单片机学习
PIC18 单片机学习(程序实例)说明:18F基本模块初始化程序均在内,且测试通过,主程序可以调用各个程序!编译器使用PICC18//程序主要用于18F单片机学习#include <pic18.h> //18系列单片机头文件//-------------函数定义--------------void delay(unsigned int rr);void timer1(void);void SPI_Iint(void); //串行SPI输出设置函数void display(void);void i2cint(void); //i2c总线初始化程序void c64R(void); //i2c接口的EEPROM存储器(读程序)void c64W(void); //写程序void Start(void); //起始位发送函数void Stop(void); //停止位发送函数void WriteWait(void); //等待函数void Senddata(unsigned char data); //数据发送函数void Restart(void); //重复启动函数void Datain(void); //数据读入void Uartint(void); //通用同步/异步收发器初始化程序void Udatas(unsigned char dad); //UART数据发送void Uartrs(void); //串口接收数据发送函数void ADint(void); //AD模块初始化void shuchai(void);//-----------数据寄存器定义----------const unsigned char table[10]={0xee,0x82,0xdc,0xd6,0xb2,0x76,0x7e,0xc2,0xfe,0xf6}; //显示段码unsigned char buf[5]; //显示缓存unsigned char receive[10]; //定义接收缓存unsigned char dd; //定时器0,中断计数寄存器unsigned char save;unsigned char conet;unsigned char *Counter; //接收数据指针unsigned char DADh; //AD缓存,unsigned char DADl;unsigned int Dat;unsigned int Dat1; //保存上次的AD转换值,用于比volatile bit DADflage; //AD转换标志volatile bit I2Cerror; //I2C错误标志volatile bit Uartsend; //异步串口数据发送允许union //联合体用来对C64的地址进行操作!{unsigned char dizhi[2];unsigned int Adress;}add;#define AddLow add.dizhi[0]#define AddHigh add.dizhi[1]#define ADDss add.Adress//***********************************//初始化//***********************************void PICint(){SWDTEN=1; //禁止看门狗,18F看门狗是可以用软件控制开启的!INTCON=0;ADCON1=0x07; //AD端口全部始能为数字IO口TRISB7=0; //设置为输出端口RB7=0;PIE1=0;PIE2=0;PIE3=0;buf[0]=0;buf[1]=0;buf[2]=0;buf[3]=0;//CMCON=0x07; //关闭比较器,18F2680没有比较器}//***********************************//高优先级中断函数//***********************************void interrupt HI_ISR(){if(TMR0IF&TMR0IE) //确认是定时器0中断{dd++;TMR0IF=0;TMR0H=0xd8; //10ms定时常数TMR0L=0xef;if(dd==100){dd=0;buf[0]++;if(buf[0]==10){buf[0]=0;buf[1]++;if(buf[1]==10){buf[1]=0;buf[2]++;if(buf[2]==10){buf[2]=0;buf[3]++;if(buf[3]==10){buf[3]=0;}}}}}}if(ADIF) //判断是否是AD转换中断{ADIF=0; //清0DADh=ADRESH;DADl=ADRESL;Dat=256*DADh+DADl;if(((Dat-Dat1)==1)||((Dat1-Dat)==1)){Dat=Dat1;}DADflage=1;}}//***********************************//低优先级中断函数//***********************************void interrupt low_priority LOW_ISR(){if(RCIF&RCIE) //如果是串口接收中断的话,则进入中断处理{RCIF=0; //清中断标志*Counter=RCREG;//读取数据到数组Counter++;if((Counter-&receive[0])==10){Counter=&receive[0];Uartsend=1;}}}//***********************************//定时器0初始化子程序//***********************************void timer1(){IPEN=1; //打开高低优先级T0CON=0x09; //把定时器0设定为16位定时器,内部时钟触发,不使用分频器TMR0IE=1; //允许定时器0溢出中断TMR0IF=0; //清除中断标志TMR0IP=1; //设定定时器0中断为高优先级TMR0H=0xD8; //定时常数TMR0L=0xef;GIE=1;PEIE=1;TMR0ON=1;}//***********************************//AD转换初始化函数//***********************************void ADint() //使用于18F2680!{ADCON0=0x01; //AD转换速率为Fosc/4,并使能AD转换模块ADCON1=0x0e; //选择为右对齐模式,并且使能AD0为模拟通道ADCON2=0x91;TRISA=1; //RA0为输入模式ADIF=0;ADIE=1; //中断使能IPEN=1; //使能高低中断优先级ADIP=1; //AD转换设置为高优先级中断GIE=1; //开总中断以及外部中断PEIE=1;DADflage=0;}//***********************************//I2C初始化函数//***********************************void i2cint(){SSPCON1=0x08; //允许串口工作,I2C主控方式,时钟=Fosc/[4*(SSPADD+1)] RC4=1; //设置为输入RC3=1;SSPADD=7; //时钟频率约为0.125MSSPSTAT=0x80; //关闭标准速度方式SSPCON2=0;SSPEN=1; //使能串口(SSP模块)I2Cerror=0;}//***********************************//SPI初始化程序//***********************************void SPI_Iint(){TRISC5=0; //SDO引脚TRISC4=1; //SDI引脚TRISC3=0; //SCK,串行时钟输出引脚TRISA5=0; //RA5为从动SS端SSPCON1=0x30; //使能串口,高电平为空闲状态,并且发送频率为fose/4,主控方式; SSPSTAT=0xc0; //时钟下降沿发送数据!SSPIF=0;conet=0;}//***********************************//通用同步/异步收发器(UART)初始化//***********************************void Uartint(){TXSTA=0x04; //设置为高速异步,方式RCSTA=0x80; //使能UARTTRISC6=0; //设置为输入,对外部呈现高阻态TRISC7=1;SPBRG=25; //设置波特率为9600//波特率计算公式//1.同步方式:波特率=Fosc/[4(X+1)]//2.异步方式:BRGH=0:波特率=Fosc/[64(x+1)]// BRGH=1:波特率=Fosc/[16(x+1)]IPEN=1; //开中断优先级RCIP=0; //串口接收使能为低优先级RCIE=1; //串口接收中断使能RCIF=0;TXIE=0; //禁止发送中断GIE=1; //开总中断和外围中断PEIE=1;TXEN=1; //使能串口发送CREN=1; //使能串口接收,注意18F是CREN而不是RCEN,编译器都认为是正确的但是RCEN不管用! Counter=&receive[0];//把数组的首地址给指针Uartsend=0;}//***********************************//AD转换函数//***********************************void ADchange(){ADCON0=ADCON0|0x02; //启动AD转换if(DADflage) //如果AD转换完成,这里采用{DADflage=0;shuchai();display();}}//***********************************//AD 数据拆分//***********************************void shuchai(){unsigned int i;Dat1=Dat; //保存这次的计数值i=Dat;buf[3]=i/1000; //取出千位i=i%1000; //取出百位数buf[2]=i/100; //取出百位数i=i%100; //取出十位数buf[1]=i/10;i=i%10;buf[0]=i;}//***********************************//Uart receive data send//***********************************void Uartrs(){if(Uartsend){unsigned char i;Uartsend=0;for(i=0;i<10;i++){Udatas(*Counter);Counter++;}Counter=&receive[0]; //重新初始化}}//***********************************//Uart 数据发送子程序//***********************************void Udatas(unsigned char dad){TXREG=dad;while(1){if(TXIF==1) break; //等待数据写入}delay(80);}//***********************************//I2C写子程序//***********************************void c64W(){Start();if(I2Cerror==1){I2Cerror=0;return; //返回防止死循环}Senddata(0xa0); //发送寻址地址,以及写操作地址!if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x00); //发送高位地址if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x40); //发送地址低字节if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x55); //发送数据if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Stop();}//***********************************//I2C读数据程序//***********************************void c64R(){Start();if(I2Cerror==1){I2Cerror=0;return; //返回防止死循环}Senddata(0xa0); //发送寻址地址,以及写操作地址!if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x00); //发送高位地址if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x40); //发送地址低字节if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Restart(); //发送重新起始位Senddata(0xa1); //发送读命令if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Datain();Stop();if(save==0x55){RB7=1;}conet++;}//***********************************//I2C重复启动//***********************************void Restart(){RSEN=1;while(1){if(SSPIF==1) break;}SSPIF=0;}//***********************************//I2C数据写等待//***********************************void WriteWait(){while(1){Start(); //在数据写入时间,如果在给器件发送数据不会有响应Senddata(0xa0);Stop();if(I2Cerror==0) break; //等待数据写入,=0则有应答位产生}}//***********************************//I2C起始位发送函数//***********************************void Start(){unsigned char i=0;SEN=1; //起始位发送while(1){i++;if(SSPIF==1) break;if(i==200) //防止死循环{i=0;I2Cerror=1;break;}}SSPIF=0;}//***********************************//I2C停止位发送//***********************************void Stop(){PEN=1;while(1){if(SSPIF==1) break;}SSPIF=0;}//***********************************//I2C数据发送函数//***********************************void Senddata(unsigned char data){unsigned char i;SSPBUF=data; //发送数据while(1){if(SSPIF==1) break;}SSPIF=0;for(i=0;i<10;i++){}if(ACKSTAT) //如果没有发出应答信号{I2Cerror=1;}else //如果发出应答信号{I2Cerror=0;}}//***********************************//I2C 数据读入函数//***********************************void Datain(){RCEN=1;while(1){if(SSPIF==1) break;}SSPIF=0;save=SSPBUF; //读数ACKDT=1; //发送非应答位ACKEN=1;while(1){if(SSPIF==1) break;}SSPIF=0;}//***********************************//164显示程序//***********************************void display() //164显示程序,用SPI端口发送数据{unsigned char i;unsigned char y,t; //传输完四个字节for(i=0;i<4;i++){y=buf[i];t=table[y];SSPBUF=t;while(1){if(SSPIF) break;}SSPIF=0;}}//***********************************//延时函数//*********************************** void delay(unsigned int rr) //延时函数{unsigned int asd;for(asd=0;asd<rr;asd++){}}//***********************************//主函数//*********************************** void main(){PICint(); //初始化函数//Uartint(); //异步串行口初始化//SPI_Iint();//ADint(); //AD模块初始化//timer1();//display();//i2cint(); //I2C初始化//c64W(); //往C64里写一次数据//WriteWait();//c64R(); //读C64里while(1){//CLRWDT();//delay(20000);CLRWDT();RB7=1;CLRWDT();SLEEP(); //等待看门狗复位RB7=0;delay(20000);CLRWDT();}}PIC18 单片机学习(程序实例)说明:18F基本模块初始化程序均在内,且测试通过,主程序可以调用各个程序!编译器使用PICC18//程序主要用于18F单片机学习#include <pic18.h> //18系列单片机头文件//-------------函数定义--------------void delay(unsigned int rr);void timer1(void);void SPI_Iint(void); //串行SPI输出设置函数void display(void);void i2cint(void); //i2c总线初始化程序void c64R(void); //i2c接口的EEPROM存储器(读程序)void c64W(void); //写程序void Start(void); //起始位发送函数void Stop(void); //停止位发送函数void WriteWait(void); //等待函数void Senddata(unsigned char data); //数据发送函数void Restart(void); //重复启动函数void Datain(void); //数据读入void Uartint(void); //通用同步/异步收发器初始化程序void Udatas(unsigned char dad); //UART数据发送void Uartrs(void); //串口接收数据发送函数void ADint(void); //AD模块初始化void shuchai(void);//-----------数据寄存器定义----------const unsigned char table[10]={0xee,0x82,0xdc,0xd6,0xb2,0x76,0x7e,0xc2,0xfe,0xf6}; //显示段码unsigned char buf[5]; //显示缓存unsigned char receive[10]; //定义接收缓存unsigned char dd; //定时器0,中断计数寄存器unsigned char save;unsigned char conet;unsigned char *Counter; //接收数据指针unsigned char DADh; //AD缓存,unsigned char DADl;unsigned int Dat;unsigned int Dat1; //保存上次的AD转换值,用于比volatile bit DADflage; //AD转换标志volatile bit I2Cerror; //I2C错误标志volatile bit Uartsend; //异步串口数据发送允许union //联合体用来对C64的地址进行操作!{unsigned char dizhi[2];unsigned int Adress;}add;#define AddLow add.dizhi[0]#define AddHigh add.dizhi[1]#define ADDss add.Adress//***********************************//初始化//***********************************void PICint(){SWDTEN=1; //禁止看门狗,18F看门狗是可以用软件控制开启的!INTCON=0;ADCON1=0x07; //AD端口全部始能为数字IO口TRISB7=0; //设置为输出端口RB7=0;PIE1=0;PIE2=0;PIE3=0;buf[0]=0;buf[1]=0;buf[2]=0;buf[3]=0;//CMCON=0x07; //关闭比较器,18F2680没有比较器}//***********************************//高优先级中断函数//***********************************void interrupt HI_ISR(){if(TMR0IF&TMR0IE) //确认是定时器0中断{dd++;TMR0IF=0;TMR0H=0xd8; //10ms定时常数TMR0L=0xef;if(dd==100){dd=0;buf[0]++;if(buf[0]==10){buf[0]=0;buf[1]++;if(buf[1]==10){buf[1]=0;buf[2]++;if(buf[2]==10){buf[2]=0;buf[3]++;if(buf[3]==10){buf[3]=0;}}}}}}if(ADIF) //判断是否是AD转换中断{ADIF=0; //清0DADh=ADRESH;DADl=ADRESL;Dat=256*DADh+DADl;if(((Dat-Dat1)==1)||((Dat1-Dat)==1)){Dat=Dat1;}DADflage=1;}}//***********************************//低优先级中断函数//***********************************void interrupt low_priority LOW_ISR(){if(RCIF&RCIE) //如果是串口接收中断的话,则进入中断处理{RCIF=0; //清中断标志*Counter=RCREG;//读取数据到数组Counter++;if((Counter-&receive[0])==10){Counter=&receive[0];Uartsend=1;}}}//***********************************//定时器0初始化子程序//***********************************void timer1(){IPEN=1; //打开高低优先级T0CON=0x09; //把定时器0设定为16位定时器,内部时钟触发,不使用分频器TMR0IE=1; //允许定时器0溢出中断TMR0IF=0; //清除中断标志TMR0IP=1; //设定定时器0中断为高优先级TMR0H=0xD8; //定时常数TMR0L=0xef;GIE=1;PEIE=1;TMR0ON=1;}//***********************************//AD转换初始化函数//***********************************void ADint() //使用于18F2680!{ADCON0=0x01; //AD转换速率为Fosc/4,并使能AD转换模块ADCON1=0x0e; //选择为右对齐模式,并且使能AD0为模拟通道ADCON2=0x91;TRISA=1; //RA0为输入模式ADIF=0;ADIE=1; //中断使能IPEN=1; //使能高低中断优先级ADIP=1; //AD转换设置为高优先级中断GIE=1; //开总中断以及外部中断PEIE=1;DADflage=0;}//***********************************//I2C初始化函数//***********************************void i2cint(){SSPCON1=0x08; //允许串口工作,I2C主控方式,时钟=Fosc/[4*(SSPADD+1)] RC4=1; //设置为输入RC3=1;SSPADD=7; //时钟频率约为0.125MSSPSTAT=0x80; //关闭标准速度方式SSPCON2=0;SSPEN=1; //使能串口(SSP模块)I2Cerror=0;}//***********************************//SPI初始化程序//***********************************void SPI_Iint(){TRISC5=0; //SDO引脚TRISC4=1; //SDI引脚TRISC3=0; //SCK,串行时钟输出引脚TRISA5=0; //RA5为从动SS端SSPCON1=0x30; //使能串口,高电平为空闲状态,并且发送频率为fose/4,主控方式; SSPSTAT=0xc0; //时钟下降沿发送数据!SSPIF=0;conet=0;}//***********************************//通用同步/异步收发器(UART)初始化//***********************************void Uartint(){TXSTA=0x04; //设置为高速异步,方式RCSTA=0x80; //使能UARTTRISC6=0; //设置为输入,对外部呈现高阻态TRISC7=1;SPBRG=25; //设置波特率为9600//波特率计算公式//1.同步方式:波特率=Fosc/[4(X+1)]//2.异步方式:BRGH=0:波特率=Fosc/[64(x+1)]// BRGH=1:波特率=Fosc/[16(x+1)]IPEN=1; //开中断优先级RCIP=0; //串口接收使能为低优先级RCIE=1; //串口接收中断使能RCIF=0;TXIE=0; //禁止发送中断GIE=1; //开总中断和外围中断PEIE=1;TXEN=1; //使能串口发送CREN=1; //使能串口接收,注意18F是CREN而不是RCEN,编译器都认为是正确的但是RCEN不管用! Counter=&receive[0];//把数组的首地址给指针Uartsend=0;}//***********************************//AD转换函数//***********************************void ADchange(){ADCON0=ADCON0|0x02; //启动AD转换if(DADflage) //如果AD转换完成,这里采用{DADflage=0;shuchai();display();}}//***********************************//AD 数据拆分//***********************************void shuchai(){unsigned int i;Dat1=Dat; //保存这次的计数值i=Dat;buf[3]=i/1000; //取出千位i=i%1000; //取出百位数buf[2]=i/100; //取出百位数i=i%100; //取出十位数buf[1]=i/10;i=i%10;buf[0]=i;}//***********************************//Uart receive data send//***********************************void Uartrs(){if(Uartsend){unsigned char i;Uartsend=0;for(i=0;i<10;i++){Udatas(*Counter);Counter++;}Counter=&receive[0]; //重新初始化}}//***********************************//Uart 数据发送子程序//***********************************void Udatas(unsigned char dad){TXREG=dad;while(1){if(TXIF==1) break; //等待数据写入}delay(80);}//***********************************//I2C写子程序//***********************************void c64W(){Start();if(I2Cerror==1){I2Cerror=0;return; //返回防止死循环}Senddata(0xa0); //发送寻址地址,以及写操作地址!if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x00); //发送高位地址if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x40); //发送地址低字节if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x55); //发送数据if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Stop();}//***********************************//I2C读数据程序//***********************************void c64R(){Start();if(I2Cerror==1){I2Cerror=0;return; //返回防止死循环}Senddata(0xa0); //发送寻址地址,以及写操作地址!if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x00); //发送高位地址if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Senddata(0x40); //发送地址低字节if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Restart(); //发送重新起始位Senddata(0xa1); //发送读命令if(I2Cerror==1){I2Cerror=0;Stop(); //错误处理return; //返回防止死循环}Datain();Stop();if(save==0x55){RB7=1;}conet++;}//*********************************** //I2C重复启动//*********************************** void Restart(){RSEN=1;while(1){if(SSPIF==1) break;}SSPIF=0;}//*********************************** //I2C数据写等待//*********************************** void WriteWait(){while(1){Start(); //在数据写入时间,如果在给器件发送数据不会有响应Senddata(0xa0);Stop();if(I2Cerror==0) break; //等待数据写入,=0则有应答位产生}}//***********************************//I2C起始位发送函数//***********************************void Start(){unsigned char i=0;SEN=1; //起始位发送while(1){i++;if(SSPIF==1) break;if(i==200) //防止死循环{i=0;I2Cerror=1;break;}}SSPIF=0;}//***********************************//I2C停止位发送//***********************************void Stop(){PEN=1;while(1){if(SSPIF==1) break;}SSPIF=0;}//***********************************//I2C数据发送函数//***********************************void Senddata(unsigned char data){unsigned char i;SSPBUF=data; //发送数据while(1){if(SSPIF==1) break;}SSPIF=0;for(i=0;i<10;i++){}if(ACKSTAT) //如果没有发出应答信号{I2Cerror=1;}else //如果发出应答信号{I2Cerror=0;}}//***********************************//I2C 数据读入函数//***********************************void Datain(){RCEN=1;while(1){if(SSPIF==1) break;}SSPIF=0;save=SSPBUF; //读数ACKDT=1; //发送非应答位ACKEN=1;while(1){if(SSPIF==1) break;}SSPIF=0;}//***********************************//164显示程序//***********************************void display() //164显示程序,用SPI端口发送数据{unsigned char i;unsigned char y,t; //传输完四个字节for(i=0;i<4;i++){y=buf[i];t=table[y];SSPBUF=t;while(1){if(SSPIF) break;}SSPIF=0;}}//***********************************//延时函数//*********************************** void delay(unsigned int rr) //延时函数{unsigned int asd;for(asd=0;asd<rr;asd++){}}//***********************************//主函数//*********************************** void main(){PICint(); //初始化函数//Uartint(); //异步串行口初始化//SPI_Iint();//ADint(); //AD模块初始化//timer1();//display();//i2cint(); //I2C初始化//c64W(); //往C64里写一次数据//WriteWait();//c64R(); //读C64里while(1){//CLRWDT();//delay(20000);CLRWDT();CLRWDT();SLEEP(); //等待看门狗复位RB7=0;delay(20000);CLRWDT();}}关于c语言流水灯程序悬赏分:20|解决时间:2010-4-13 17:04|提问者:chenli6522002流水灯怎么在下面代码中不能点亮,出现什么问题了?#include "reg51.h"char led[]={0x01,0x02,0x04,0x08};char led1[]={0x01,0x04,0x02,0x08,0x08,0x02,0x04,0x01};char led2[]={0x08,0x04,0x02,0x01};void delay(unsigned int time){ unsigned int j;for(;time>0;time++)for(j=0;j<125;j++);}void main(){char i;while(1){if(P0==0x0e)while(1){for(i=0;i<=3;i++){P2=led[i];delay(200);}if(P0==0x0d||P0==0x0d)break;}else if(P0==0x0d)while(1)for(i=0;i<=3;i++){P2=led1[i];delay(200);}if(P0==0x0b||P0==0x0e) break;}else if(P0==0x0b)while(1){for(i=0;i<=3;i++){P2=led2[i];delay(200);}if(P0==0x0e||P0==0x0d)break;}else P2=0;}}最佳答案如果是流水灯你使用一下程序会更好简单实现的功能是P1 P3口的流水灯循环闪动你可以参照这个写..使用位控制#include "reg51.h"void main(){unsigned int i=10;P1=0xfe;while(1){while(--i){;}P1=(P1<<1) | 0x01;if(P1==0xff) P3 = 0x7f;while(P1==0xff){while(--i){;}P3=(P3>>1) | 0x80;{P1=0xfe;P3=0xff;}}}}音响程序#define uchar unsigned char //定义一下方便使用#define uint unsigned int#define ulong unsigned long#include <reg52.h> //包括一个52标准内核的头文件char code dx516[3] _at_ 0x003b;//这是为了仿真设置的sbit BEEP=P1^7; //喇叭输出脚sbit P10=P1^0;sbit K1= P3^2;sbit K2= P3^5;sbit K3= P2^4;sbit K4= P2^5;uchar th0_f; //在中断中装载的T0的值高8位uchar tl0_f; //在中断中装载的T0的值低8位//T0的值,及输出频率对照表uchar code freq[36*2]={0xA9,0xEF,//00220HZ ,1 //00x93,0xF0,//00233HZ ,1#0x73,0xF1,//00247HZ ,20x49,0xF2,//00262HZ ,2#0x07,0xF3,//00277HZ ,30xC8,0xF3,//00294HZ ,40x73,0xF4,//00311HZ ,4#0x1E,0xF5,//00330HZ ,50xB6,0xF5,//00349HZ ,5#0x4C,0xF6,//00370HZ ,60xD7,0xF6,//00392HZ ,6#0x5A,0xF7,//00415HZ ,70xD8,0xF7,//00440HZ 1 //120x4D,0xF8,//00466HZ 1# //130xBD,0xF8,//00494HZ 2 //140x24,0xF9,//00523HZ 2# //150x87,0xF9,//00554HZ 3 //160xE4,0xF9,//00587HZ 4 //170x3D,0xFA,//00622HZ 4# //180x90,0xFA,//00659HZ 5 //190xDE,0xFA,//00698HZ 5# //200x29,0xFB,//00740HZ 6 //210x6F,0xFB,//00784HZ 6# //220xB1,0xFB,//00831HZ 7 //230xEF,0xFB,//00880HZ `10x2A,0xFC,//00932HZ `1#0x62,0xFC,//00988HZ `20x95,0xFC,//01046HZ `2#0xC7,0xFC,//01109HZ `30xF6,0xFC,//01175HZ `40x22,0xFD,//01244HZ `4#0x4B,0xFD,//01318HZ `50x73,0xFD,//01397HZ `5#0x98,0xFD,//01480HZ `60xBB,0xFD,//01568HZ `6#0xDC,0xFD,//01661HZ `7 //35};//定时中断0,用于产生唱歌频率timer0() interrupt 1{TL0=tl0_f;TH0=th0_f; //调入预定时值BEEP=~BEEP; //取反音乐输出IO}//******************************//音乐符号串解释函数//入口:要解释的音乐符号串,输出的音调串,输出的时长串changedata(uchar *song,uchar *diao,uchar *jie){uchar i,i1,j;char gaodi; //高低+/-12音阶uchar banyin;//有没有半个升音阶uchar yinchang;//音长uchar code jie7[8]={0,12,14,16,17,19,21,23}; //C调的7个值*diao=*song;{gaodi=0; //高低=0banyin=0;//半音=0yinchang=4;//音长1拍if((*(song+i)=='|') || (*(song+i)==' ')) i++; //拍子间隔和一个空格过滤switch(*(song+i)){case ',': gaodi=-12;i++;//低音break;case '`': gaodi=12;i++; //高音break;}if(*(song+i)==0) //遇到0结束{*(diao+i1)=0; //加入结束标志0*(jie+i1)=0;return;}j=*(song+i)-0x30; i++; //取出基准音j=jie7[j]+gaodi; //加上高低音yinc: switch(*(song+i)){case '#': //有半音j加一个音阶i++;j++;goto yinc;case '-': //有一个音节加长yinchang+=4;i++;goto yinc;case '_': //有一个音节缩短yinchang/=2;i++;goto yinc;case '.': //有一个加半拍yinchang=yinchang+yinchang/2;i++;goto yinc;}*(diao+i1)=j; //记录音符*(jie+i1)=yinchang; //记录音长i1++;}}//******************************************//奏乐函数//入口:要演奏的音乐符号串void play(uchar *songdata){uchar i,c,j=0;uint n;uchar xdata diaodata[112]; //音调缓冲uchar xdata jiedata[112]; //音长缓冲changedata(songdata,diaodata,jiedata); //解释音乐符号串TR0=1;for(i=0;diaodata[i]!=0;i++) //逐个符号演奏{tl0_f=freq[diaodata[i]*2]; //取出对应的定时值送给T0th0_f=freq[diaodata[i]*2+1];for(c=0;c<jiedata[i];c++) //按照音长延时{for(n=0;n<32000;n++);if((!K1)||(!K2)||(!K3)||(!K4))//发现按键,立即退出播放{TR0=0;return;}}TR0=0;for(n=0;n<500;n++); //音符间延时TR0=1;}TR0=0;}//仙剑uchar code xianjian[]={"|3_3_3_2_3-|2_3_2_2_,6,6_,7_|12_1_,7,6_,5_|,6---|" "3_3_3_2_3.6_|5_6_5_5_22_3_|45_4_32_1_|3.--3_|" "67_6_55_3_|5--3_5_|26_5_32_3_|3---|""26_6_6-|16_6_66_7_|`17_6_76_7_|3.--3_|""67_6_55_3_|5--3_5_|67_6_76_7_|3---|""26_6_6-|16_6_66_7_|`17_6_7.5_|6---|"};uchar code song3[]={"5-5_3_2_1_|3---|6-6_4_2_1_"",7--,5_|1.3_5.1_|,7.3_5 5_|""6.7_`1.6_|6_5_5-3_2_|1.1_13_2_|""1.1_12_3_|2.1_,62_3_|2-- ,5_|""1.3_5.1_|,7.3_55_|6.7_`1.6_|""6_5_5-3_2_|1.1_13_2_|1.1_12_3_""2.,6_,71_2_|1--"};//世上只有妈妈好uchar code mamahao[]={"6.5_35|`16_5_6-|35_6_53_2_|1_,6_5_3_2-|""2.3_55_6_|321-|5.3_2_1_,6_1_|,5--"};//三个按键选择三首不同的音乐播放,一个键停止播放void main(void) // 主程序{TMOD = 0x01; //使用定时器0的16位工作模式TR0 = 0;ET0 = 1; //定时器0中断EA = 1; //打开总中断while(1){if(!K1){while(!K1);play(xianjian); //播放音乐}if(!K2){while(!K2);play(song3); //播放音乐}if(!K3){while(!K3);play(mamahao); //播放音乐}}}延时程序(包括asm和C程序,都是我在学单片机的过程中用到的),在单片机延时程序中应考虑所使用的晶振的频率,在51系列的单片机中我们常用的是11.0592MHz和12.0000MHz的晶振,而在AVR单片机上常用的有8.000MHz和4.000MH的晶振所以在网上查找程序时如果涉及到精确延时则应该注意晶振的频率是多大。
PIC18系列单片机原理及实践
PIC18系列单片机是一种非常常用的微控制器,本课程将通过理论与实践相 结合的方式,详细介绍该系列单片机的原理和应用。
PIC18单片机系列概述
PIC18单片机系列广泛应用于嵌入式系统,具有强大的处理能力和丰富的外设功能。本节课将介绍其特 点、应用领域和优势。
强大的处理能力
2
对电流、电压和功率的控制。
PIC18单片机可以通过PWM输出来控
制LED的亮度,实现动态调节效果。
3
电机速度控制
利用PWM输出可以控制电机的转速, 实现精确的速度控制。
定时器与中断的应用
定时器和中断是PIC18单片机重要的功能模块。本节课将介绍定时器的原理和中断的应用方法。
定时器 中断ቤተ መጻሕፍቲ ባይዱ
通过定时器模块可以实现精确的时间计量和延 时控制。
1
需求分析
明确系统的功能需求和性能指标。
硬件设计
2
选择适合的单片机和外围电路,并进
行电路设计。
3
软件设计
编写单片机的程序代码,实现系统的
系统集成
4
功能。
将硬件和软件部分进行整合,并进行 调试和测试。
开发工具的选择与环境配置
选择合适的开发工具和环境对于单片机开发非常重要。本节课将介绍开发工具的选择准则和环境配置的 步骤。
2 汇编语言
更接近硬件,可以对单片机进行更细致的控制,适合对性能要求较高的应用。
I/O口及外设的应用方法
通过I/O口和外围设备,PIC18单片机可以与外部世界进行信息交互。本节课将介绍I/O口的基本原理和 外设的应用方法。
I/O口基本原理
外设的应用方法
I/O口用于输入和输出数字信号, 通过设置和读取I/O口寄存器来 实现。
简单使用PIC18F458调用CAN的C代码
简单使用PIC18F458调用CAN的C代码笔者是一个软件超级懒人,向来喜欢摘抄网上的代码为自己所用,最近涉及一CAN软件,用了一天,偷懒成功,特为诸多开发同胞们提高工作效率,早日回家抱老婆睡觉,特献此代码,不对之处请多多指教。
1、先在microchip网站上找到00738.zip,这个包中有can18xx8.h,can18xx8.c,将其复制到一个你要编写程度的子目录中,例如C:\ testcan下,这个时候这个东东是不能直接用的。
2、下载一个MPLAB 7.10,直接安装(要求直接下载)3、再下载一个PICC18 (HI-TECH的),要正版哦(支持正版,买不起的想其它办法吧)4、在你的头文件上写上如下的样式:#include "stdio.h"#include "can18xx8.h"#include "pic18fxx8.h"//可能是“pic.h”不太好包含,因此常会报错,直接包含克服之5、然后设置好PICC和MPLAB,如果MPLAB上没有PICC18,则到PICC的网上下一个安装软件,可以直接运行安装就有了。
6、按照工程的基本要求把你的源代码、添加上两个库(不加也可以)然后就可以写如下代码了:下面是一个完整版,可以直接使用microchip的库函数,本程序只是仿真调试过,未在多个芯片通信过,仍在制作中。
#include "stdio.h"#include "can18xx8.h"#include "pic18fxx8.h"unsigned long NewMessage;BYTE NewMessageData[8];BYTE MessageData[8];BYTE NewMessageLen;enum CAN_RX_MSG_FLAGS NewMessageFlags=1;BYTE RxFilterMatch;void main(){//int a;//int b;CANInitialize(1, 5, 7, 6, 2, CAN_CONFIG_VALID_XTD_MSG);while(1){// Application specific logic here// Check for CAN messageif ( CANIsRxReady() ){CANReceiveMessage(&NewMessage,NewMessageData,&NewMessageLen,&NewMessa geFlags);if ( NewMessageFlags & CAN_RX_OVERFLOW ){// Rx overflow occurred; handle it}if ( NewMessageFlags & CAN_RX_INVALID_MSG ){// Invalid message received; handle it}if ( NewMessageFlags & CAN_RX_XTD_FRAME ){// Extended Identifier received; handle it}else{// Standard Identifier received.}if ( NewMessageFlags & CAN_RX_RTR_FRAME ){// RTR frame received}else{// Regular frame received.}// Extract receiver filter match, if it is to be usedRxFilterMatch = NewMessageFlags & CAN_RX_FILTER_BITS;}// Process received message// Transmit a message due to previously received message or// due to application logic itself.if ( CANIsTxReady() ){MessageData[0] = 0x01;CANSendMessage( 0x02,MessageData,1,CAN_TX_PRIORITY_0&CAN_TX_STD_FRAME &CAN_TX_NO_RTR_FRAME);}// Other application specific logic} // Do this forever// End of program}以上均是参考<PIC18C CAN Routines in ‘C’.pdf>文档并进行了修正,由于中间总是报错,为了大家让CAN更容易,谢谢大家!。
PIC18F452单片机原理及编程实践(第十章)PIC 18串行接口的汇编和C编程
计算机内部的数据是按字节存储、运算的; 计算机与外部设备之间的数据传输从理论上讲:采用并 行方式是效率最高的,因为并行传输数据的速度快; 如果两套设备之间距离变长,则不得不考虑下列因素: 数据传输设备的成本:并行设备至少要8条以上的线; 随着距离的加长,信号幅值将要衰减、干扰信号的影响 将显著增加。 因此长距离通信采用串行传输方式必然结果。
第十章 PIC 18串行接口的汇编和C编程
1. 2. 3. 4. 5. 6. 7. 8. 9.
本章内容: 串行通信和并行通信,串行通信的优点; 串行通信的协议; 同步串行和异步串行; 半双工和全双工传输; 数据帧格式; 串行数据传输速度和波特率,PIC18的波特率; RS-232标准及MAX232芯片的应用; PIC18串行通信的特征以及相关的寄存器; 使用汇编和C语言对PIC18串行口的编程。
RS232 电平
TX RX
MAX232
MAX232
RX TX
PIC18甲乙两地之间远距离通讯(RS-232电平)
TX RX MAX232 PC机 COM1,COM2
PIC18与PC机之间的数据通讯(RS-232电平)
2017/8/29 14
10.2.1 PIC18的串行接口模块
1. 2.
具备同步、异步的全双工的功能模块; 在PIC18单片机中有两个引脚是用于串行通信的: RX --- 串行数据接收端(RC7); TX --- 串行数据发送端(RC6)。 当使能串口模块时要通过TRISC的相关位的引脚方向进 行设置(BCF TRISC,6 和 BSF TRISC,7)。 主要的相关SFR寄存器: SPBGR:波特率寄存器); TXSTA、 RCSTA:发送状态、接收状态寄存器; TXREG、RCREG:发送数据、接收数据缓冲器。
PIC18F单片机的中断嵌套的C语言编程方法
PIC18F单片机的中断嵌套的C语言编程方法PIC18F4520单片机提供多个中断源及一个中断优先级功能,可以给大多数中断源分配高优先级或者低优先级.高优先级中断向量地址为0008H,低优先级中断向量地址为0018H。
高优先级中断事伯将中断所有可参正在进行的低优先级中断。
有10个寄存器用于控制中断的操作。
它们是:RCONINTCONINTCON2INTCON3PIR1和PIR2PIE1和PIE2IPR1和IPR2通常,用三个位控制中断源的操作。
它们是:标志位表明发生了中断事件使能位允许程序跳转转到中断向量地址处执行(当标志位置1时)优先级用于选择是高优先级还是低先级通过将IPEN位(RCON<7>)置1,可使能中断优先级功能。
当使能中断优先级时,有2位可使能全局中断。
将GIEH位(INTCON<7>)置1,可使能所有优先级位置1(高优先级)的中断。
将GIEL位(INTCON<6>)置1,可使能所有优先级位清零(低优先级)的中断。
当中断标志位、使能位以及相应的全局中断使能位均被置1时,程序将立即跳转到中断地址0008H或0018H,具体地址取决于优先级位的设置。
通过设置相应的使能位可以禁止单个中断。
注意:系统复位时IPEN位为零(默认状态)时,便会禁止中断优先级功能,此时中断与PIC16系统中档单片机相兼容。
在兼容模式下,所有中断均跳转到地址0008H执行。
下面是在SP9608-PIC增强型单片机开发板利用PIC18F4520单片机来实现的数字频率计数器功能,程序中使用了T0用为外部信号源输入,通TMR0来实现对信号源的频率计数。
TMR3作为定时器,来产生1mS数码管扫描时基和1S秒时基信号。
为了提高频率计数的准确度,采用中断嵌套技术来完成,将TMR3产生1mS的定时信号作为高优先级中断,TMR0作为频率计数溢出中断作为低先级中断。
源程序采用MCC18编译器和MPLAB7.50版本的集成开发环境,调试工具采用ICD2;具体源程序如下:系统时钟:采用外部的12MHz晶振经过内部PLL的4倍频到48MHz。
利用PIC18FXX8进行CAN总线系统节点设计
第 30 卷第 10 期2004 年 10 月电子工程师ELEC TRONIC ENGINEERVol. 30 No. 10Oct. 2004利用 PIC18FXX8 进行 CAN 总线系统节点设计朱 芳(无锡科技职业学院 , 江苏省无锡市 214028)【摘 要】 采用带在片 C AN 的微控制器 PIC18FXX8 进行 C AN 总线系统智能节点的硬件电路设 计和软件设计 。
硬件电路设计时为了增强 C AN 总线节点抗干扰能力 ,采用 MICROCHIP 公司的 C AN 总 线驱动器 MCP2551 ,并通过高速光耦 6N137 与 MCP2551 相连 ,很好地实现了总线上各 C AN 节点间的电 气隔离 ;软件设计包括 PIC18FXX8 的 C AN 模块的初始化 、查询方式发送子程序和查询方式接收子程序 等应用中最基本的子程序 。
软件程序采用汇编语言编写 ,在实际应用中可采用 C 语言编写 。
关键词 :总线 , 节点 , C AN , PIC18FXX8中图分类号 : T N334. 70 引 言在 C AN 总线的通信协议中 , 没有节点地址的概念 ,也不存在与节点地址相关的信息 ,它支持的是基于 数据的工作方式 。
亦即 ,CAN 总线面向数据而不是节 点 ,因此加入或撤消节点设备都不影响网络工作 ,这种 结构十分适用于控制系统快速 、可靠 、简明的特点 。
目前流行的 C AN 总线器件有两大类 :一类是独立 的 C AN 控制器 ,例如 82C200 、SJA1000 及 Intel 公司的 82526 和 82527 芯片等 ; 另一类是带在片 C AN 的微控 制器 ,例如 P8XC592 、Mot or ol a 的 MC68HC05X 系列等 。
在实际应用中 ,为了使硬件电路设计简单 ,并提高系统 的整体性能 ,往往采用带在片 C AN 的微控制器 。
本文 以 MICROCHIP 公司的 PIC18FXX8 系列微控制器为例 , 介绍 C AN 总线系统节点的硬件和软件设计 。
利用PIC18FXX8进行CAN总线系统节点设计
利用PIC18FXX8进行CAN总线系统节点设计
朱芳
【期刊名称】《电子工程师》
【年(卷),期】2004(30)10
【摘要】采用带在片CAN的微控制器PIC1 8FXX8进行CAN总线系统智能节点的硬件电路设计和软件设计。
硬件电路设计时为了增强CAN总线节点抗干扰能力 ,采用MICROCHIP公司的CAN总线驱动器MCP2 5 5 1 ,并通过高速光耦 6N1 37与MCP2 5 5 1相连 ,很好地实现了总线上各CAN节点间的电气隔离 ;软件设计包括PIC1 8FXX8的CAN模块的初始化、查询方式发送子程序和查询方式接收子程序等应用中最基本的子程序。
软件程序采用汇编语言编写 ,在实际应用中可采用C 语言编写。
【总页数】3页(P13-15)
【关键词】总线;节点;CAN;PIC18FXX8
【作者】朱芳
【作者单位】无锡科技职业学院
【正文语种】中文
【中图分类】TN334.7
【相关文献】
1.利用P8xC591进行汽车CAN总线系统智能节点的设计 [J], 李文言;姜竹胜;孙启启
2.利用MCP25050设计CAN总线前端测控节点 [J], 曹燕;陶彦辉;吴学伍
3.利用MCP25050设计CAN总线前端测控节点 [J], 曹燕;陶彦辉;吴学伍
4.高速SpaceFibre总线节点的系统设计 [J], 祝平;朱岩;安军社;江源源;周莉
5.利用CAN总线实现多台簇绒机互联的智能节点模块设计 [J], 郭火平;朱文因版权原因,仅展示原文概要,查看原文内容请购买。
用PIC18F458的CAN模块实现CAN总线通信
用 PIC18F458 的 CAN 模块实现 CAN总线通信 ■ 重庆大学 周有为 刘和平CAN(Controller Area Network)即控制器区域网,是一 种主要用于各种设备监测及控制的网络。
CAN 具有独特 的设计思想, 良好的功能特征和极高的可靠性, 现场抗 干扰能力强。
其在国内外工业控制领域已经被广泛应 用, 成为最有发展前途的现场总线之一。
美国微芯公司的 PIC18F458 单片机集成了 CAN 通信 接口, 执行 Bosch 公司的 CAN2.0A/B 协议。
它能支持 CAN1.2 、 CAN2.0A 、 CAN2.0B 协议的旧版本和 CAN2.0B 现行版本。
使用 PIC18F458 单片机的嵌入式系统, 可以很方便的利用 C A N 总线与外界进行数据交换。
它的优 点是电路接口比较简单, 只需很少的外围电路就可实现 C AN 通信, 受硬件限制比较少; 软件编程容易实现所需 功能, 只需对相关寄存器进行正确设置即可。
1 硬件接口电路PIC18F458 与 CAN 驱动芯片 PCA82C250T 的接口电路 如图 1 所示。
PCA82C250T 是驱动 CAN 控制器和物理总 线间的接口, 提供对总线的差动发送和接收功能。
电阻 R 作为 CA N 终端的匹配电阻; 电感 L 起滤波作用。
2 CAN 控制器的操作2.1 初始化 CAN 控制在使用 C AN 之前, 必须对它的一些内部寄存器进行 设置, 如 C A N 控制寄存器 C A N C O N 、 波特率寄存器 B R GC ON x 的设置以及对邮箱进行初始化。
波特率寄存器 BRGCONx(x=1, 2, 3)决定了 CAN 控制 器的波特率、 采样次数、 同步跳转宽度和重同步方式, 对波特率寄存器的配置步骤如下 :① 设置 CAN CON 寄存器中的 CAN 操作方式请求位为 1xx , 即 REQOP=1xx ;② 判断 CANSTAT 寄存器中的操作方式状态位是否为 100 , 即 OPMODE 是否为 100 , 如 OPMODE=100 则进入 下一步 ; ③ 设置 BRGCONx(x=1, 2, 3)寄存器, 即配置正确的 波特率, 同步跳转宽度、 采样次数和重同步方式 ;④ 设置发送邮箱和接收邮箱的标识符、 邮箱数据 长度、 屏蔽寄存器、 滤波寄存器以及初始化邮箱的数 据区 ; ⑤ 设置CA NCON 寄存器中的 CAN 操作方式请求位 为 000, 即 REQOP=000, 使 CAN 模块进入正常工作方式; ⑥ 判断 CANSTAT 寄存器中的操作方式状态位是否 为 000 , 即 OPMODE 是否为 000 , 如 OPMODE=000 则进入 下一步 ;⑦ 寄存器配置和邮箱初始化完成后, 进入正常工作 方式。
PIC18 C语言实例
void InterruptHandlerHigh () {
INTCONbits.RBIF=0; DELAY(); PORTB=PORTB;
if(PORTBbits.RB4==0) {
KEYSERVE(); PORTBbits.RB1=0; PORTAbits.RA3=0; PORTE=0;
INTCONbits.RBIF=0;
/*初始化子程序*/ void initial() {
TRISA=0x00; TRISC=0x00; INTCON=0x00; SSPCON1=0x30; SSPSTAT=0xC0; PIR1=0; }
/*A 口设置为输出*/ /*SDO 引脚为输出,SCK 引脚为输出*/ /*关闭所有中断*/ /*SSPEN=1;CKP=1,FOSC/4*/ /*时钟下降沿发送数据*/ /*清除 SSPIF 标志*/
#include "p18f458.h" main() {
TRISD=0X00; PORTD=0XFF; while(1) {
PORTD=0XAA; } }
/*TRISD 寄存器被赋值,PORTD 每一位都为输出*/ /*向 PORTD 送 0XFF,熄灭所有 LED*/ /*循环执行点亮发光二极管的语句*/
PORTAbits.RA5=0; SSPBUF=data; do { ; }while(PIR1bits.SSPIF==0); PIR1bits.SSPIF=0; PORTAbits.RA5=1; }
/*LACK 送低电平,为锁存做准备*/ /*启动发送*/
/*等待发送完毕*/ /*清除 SSPIF 标志*/ /*最后给锁存信号,代表显示任务完成*/
/*初始化子程序*/ void initial() {
PIC18FXX8单片机通用同步异步收发器的接口电路和C源代码
PIC18FXX8单片机通用同步异步收发器的接口电路和C源代码摘要:本文介绍了Microchip 公司推出的PIC18FXX8 单片机通用同步异步收发器USART(串行通信接口)的相关内容,给出了单片机该模块的接口电路和C 语言应用编程。
0 引言PIC18Fxx8 单片机是美国微芯公司推出的16 位RISC 指令集的高级产品,由于芯片内含有A/D、内部E2PROM 存储器、I2C和SPI 接口、CAN 接口、同步/异步串行通信(USART)接口等强大的功能,具有很好的应用前景。
但是,目前介绍其应用和以C 语言编程的中文参考资料很少。
本文将探讨该型单片机异步串行通信的编程应用,程序用HI-TECH PICC-18 C 语言编写,并在重庆大学-美国微芯公司PIC 单片机实验室的PIC18F458 实验板上通过。
1 PIC18FXX8 单片机同步/异步收发器(USART)通用同步/异步收发器(USART)模块是由PIC18FXX8 内的三个串行I/O 模块组成的器件之一(USART 也叫串行通信接口即SCI),可以配置为全双工异步方式、半双工同步主控方式、半双工同步从动方式三种工作方式。
TXSTA 是PIC18FXX8 单片机串行通信发送状态和控制寄存器,RCSTA 是接收状态和控制寄存器。
由于在实际工程中,异步方式用得最多,这里仅介绍异步工作方式,其它方式可参阅相关资料。
1.1 USART 异步工作方式在异步工作方式下,串行通信接口USART 采用标准的不归零(NRZ)格式(1 位起始位、8 位或9 位数据位和一位停止位),最常用的数据位是8 位。
片内提供的8 位波特率发生器BRG 可用来自振荡器时钟信号产生标准的波特率频率。
通过对SYNC 位(在TXSTA 寄存器中)清零,可选择USART 异步工作方式。
1.2 USART 波特率发生器(BRG)USART 带有一个8 位的波特率发生器(BRG),这个。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
pic18fxx8单片机通用同步异步收发器的接口电路和c源代码时间:2012-06-01 18:58:19 来源: 摘要:本文介绍了Microchip公司推出的PIC18FXX8单片机通用同步异步收发器USART (串行通信接口)的相关内容,给出了单片机该模块的接口电路和C语言应用编程。
0 引言PIC18Fxx8单片机是美国微芯公司推出的16位RISC指令集的高级产品,由于芯片内含有A/D、内部E2PROM存储器、I2C和SPI接口、CAN接口、同步/异步串行通信(USART)接口等强大的功能,具有很好的应用前景。
但是,目前介绍其应用和以C语言编程的中文参考资料很少。
本文将探讨该型单片机异步串行通信的编程应用,程序用HI-TECH PICC-18 C语言编写,并在重庆大学-美国微芯公司PIC单片机实验室的PIC18F458实验板上通过。
1 PIC18FXX8单片机同步/异步收发器(USART)通用同步/异步收发器(USART)模块是由PIC18FXX8内的三个串行I/O模块组成的器件之一(USART也叫串行通信接口即SCI),可以配置为全双工异步方式、半双工同步主控方式、半双工同步从动方式三种工作方式。
TXSTA是PIC18FXX8单片机串行通信发送状态和控制寄存器,RCSTA是接收状态和控制寄存器。
由于在实际工程中,异步方式用得最多,这里仅介绍异步工作方式,其它方式可参阅相关资料。
1.1 USART 异步工作方式在异步工作方式下,串行通信接口USART采用标准的不归零(NRZ)格式(1位起始位、8位或9位数据位和一位停止位),最常用的数据位是8位。
片内提供的8位波特率发生器BRG可用来自振荡器时钟信号产生标准的波特率频率。
通过对SYNC位(在TXSTA寄存器中)清零,可选择USART异步工作方式。
1.2 USART波特率发生器(BRG)USART带有一个8位的波特率发生器(BRG),这个BRG支持USRAT的同步方式和异步方式。
用SPBRG寄存器控制一个独立的8位定时器的周期。
在异步方式下,BRGH位(控制寄存器TXSTA的)也被用来控制波特率。
在同步方式下,用不到BRGH位。
表1给出了在主控方式下(内部时钟)不同USART工作方式时的波特率计算式。
表1 主控方式下的波特率计算式SYNC BRGH=0(低速)BRGH=1(高速)0 (异步)波特率=F OSC/[64(X+1)] 波特率 = F OSC/[16(X+1)]1 (同步)波特率=F OSC/[4(X+1)]无1.3 USART 异步工作方式配置下面是串行通信异步工作方式配置步骤(顺序可以改变):(1)配置发送状态和控制寄存器TXSTA;(2)配置接收状态和控制寄存器RCSTA;(3)配置RX(RC7引脚)、TX(RC6引脚)分别为输入和输出方式;(4)通过设定的通信波特率配置SPBRG寄存器,计算公式参见表1;(5)设置串行通信接收或发送中断是否使能;(6)清串行通信接收或发送中断标志;(7)设置串行通信接收中断或发送中断的优先级是高或低优先级中断方式,PIC18单片机默认情况下是高优先级中断,若是低优先级中断,则必须进行设置;(8)设置串行通信接收和发送数据是否允许。
若用到了中断功能,还需设置总中断和外围中断使能,以开放未屏蔽的中断。
2 USART接口硬件电路利用PC机配置的串行口,可以很方便地实现PC机与PIC18单片机的串行数据通信。
PC机与PIC单片机USART连接最简单的是三线方式。
由于PIC单片机输入、输出电平为TTL电平,而RS-232C PC机配置的是RS-232C标准串行接口,二者电气规范不一致,因此要完成PC机与微控制器的串行数据通信,必须进行电平转换。
图1为PIC18F458单片机的RS-232电平转换电路。
图中MAX232(或MAX202)将PIC18单片机TX输出的TTL电平信号转换为RS-232C电平,输入到PC机,并将PC机输出的RS232C电平信号转换为TTL电平输出到PIC微控制器的RX引脚。
J9和PC机的连接方式见RS-232标准,与单片机相接的D型头(J9)的2脚(PIC接收信号)与接PC机D型头的3脚(PC机发送信号)相连,与单片机相接的D型头(J9)的3脚(PIC发送信号)与接PC机D型头的2脚(PC机接收信号)相连,二者的5脚与5脚相连(地相连)。
PC机串口数据的发送和接收显示均可采用各种串口调试软件,我们使用的是串口调试助手V2.2(或V2.1、V2.0均可),在网上可以下载该调试软件,该软件操作简单,这里不作介绍。
3 USART异步工作方式编程串行通信的接收有查询和中断2种方式,在实际应用中,一般不采用查询接收数据,常用的是中断接收数据。
发送有中断发送和非中断发送,在下面的例程中我们采用了中断接收数据,发送数据采用中断方式还是非中断方式可以在程序中通过对发送方式标志Send_Mode(不为0,中断方式发送;=0,非中断方式发送)进行设置实现。
在PIC单片机发送数据时,发送中断标志TXIF不能用软件清0,只有当新的发送数据送入发送数据寄存器TXREG后,TXIF位才能被硬件复位,因此在程序中清该标志是无效的。
采用中断发送数据的方法是:在主程序中启动发送一串数据的第一个数据,然后利用发送完成中断启动下一个数据发送,当一串数据发送后,不再发送数据,但有发送完成中断标志,程序还要进入一次中断,这最后一次中断对数据发送是无用的,必须将该标志清0,采用的方法是禁止发送使能(TXEN=0)而引起发送被终止或对发送器复位。
下面是一个用串行通信进行接收和发送数据的例程,程序实现功能:PIC18单片机接收到PC机下发的8个数据后,将收到的8个数据以中断或非中断发送方式返送回PC机。
#include "pic18.h" /* PIC18系列的头文件 */unsigned char receive232[8]; /* 接收数据数组 */unsigned char send232[8]; /* 发送数据数组 */unsigned char receive_count=0; /* 接收数据个数计数 */unsigned char send_count=0; /* 发送数据个数计数 */unsigned char *pointer; /* 发送数据指针 */unsigned char i; /* 程序中用到的循环变量 */unsigned char SciReceiveFlag; /* =1,接收到8个数据 */unsigned char Send_Mode=0; /* 不为0,中断方式发送;=0,非中断方式发送 */void sciinitial() /* 串行通讯初始化子程序 */{TXSTA=0x04; /* 选择异步高速方式传输8位数据 */RCSTA=0x80; /* 允许串行口工作使能 */TRISC=TRISC|0X80; /* :将RC7(RX)设置为输入方式 */TRISC=TRISC&0Xbf; /* RC6(TX)设置为输出 */SPBRG=25; /* 4M晶振且波特率为9600时,SPBRG设置值为25 */PIR1=0x00; /* 清中断标志 */PIE1=PIE1|0x20; /* 允许串行通讯接口接收中断使能 */RCIP=0; /* 设置SCI接收中断为低优先级中断 */CREN=1; /* 允许串口连续接收数据 */if(0==Send_Mode) TXEN=1; /* Send_Mode=0,非中断方式发送,串口发送数据使能 */ else /* Send_Mode=1,中断方式发送 */{PIE1=PIE1|0x10; /* 允许中断发送 */TXIP=0; /* 发送低优先级中断 */}}void interrupt low_priority LOW_ISR() /* 低优先级中断子程序 */{if(RCIF==1) /* RS232接收中断 */{RCIF=0; /* 清中断标志 */receive232[receive_count]=RCREG; /* 接收数据并存储 */send232[receive_count]=RCREG; /* 接收数据存放到发送缓冲数组 */receive_count++; /* 接收计数器加1 */if(receive_count>7) /* 如果已经接收到8个数据 */{receive_count=0; /* 接收计数器清0 */SciReceiveFlag=1; /* 置接收到8个数据标志 */}}else if((0!=Send_Mode)&&(TXIF==1)) /* 中断发送数据方式且为发送中断 */{if(send_count>7) /* 已经发送完8个数 */{TXEN=0; /* 发送不使能 */return;}else{send_count++; /* 发送计数器加1 */TXREG=*pointer++; /* 发送当前应发送数据,发送指针加1 */ }}}main() /* 主程序 */{INTCON=0x00; /* 关总中断 */ADCON1=0X07; /* 设置数字输入输出口,不用作模拟口 */PIE1=0; /* PIE1 的中断不使能 */PIE2=0; /* PIE2 的中断不使能 */PIE3=0; /* PIE3 的中断不使能 */Send_Mode=1; /* Send_Mode不为0,中断方式发送数据;Send_Mode =0,非中断方式发送数据 */sciinitial(); /* 串行通讯初始化子程序 */IPEN=1; /* 使能中断高低优先级 */INTCON=INTCON|0xc0; /* 开总中断、开外围接口中断 */while(1){if(1==SciReceiveFlag) /* 是否接收到8个通信数据 */{SciReceiveFlag=0; /* 清接收到8个通信数据标志 */if(0!=Send_Mode) /* Send_Mode不为0,中断方式发送 */ {send_count=0; /* 发送数据计数清0 */pointer=&send232[0]; /* 发送指针指向发送数据数组首地址 */TXREG=*pointer++; /* 发送第一个数据后,将发送指针加1 */ TXEN=1; /* 使能发送 */}else /* Send_Mode =0,非中断方式发送数据 */{pointer=&send232[0]; /* 发送指针指向发送数据数组首地址 */ for(i=0;i<8;i++){TXREG=*pointer++; /* 发送数据后,将发送指针加1 */while(1) /* 等待发送完成 */{if(TXIF==1) break; /* 等待发送完成 */}}}}}}原文网址: /app/mcu/index_4.htm。