实例 供参考 可以直接仿真,多看看实例 会有帮助的。
*********************************************************************
* GPIO0-V GPIO1-I GPIO2-LED1 GPIO4-LED2 GPIO5-OUT *
* GPIO3-10K *
*********************************************************************
LIST P=12F675
INCLUDE "P12F675.INC" 包含MPLAB预定义的头文件
__CONFIG(0x3FC4) 11 ---1 1100 1000 设定配置字信息
_CPD_OFF & _CP_OFF & _BODEN_ON & _MCLRE_OFF
关代码-数据保护, 掉电复位使能,内部复位,
_PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT
歼答 上电复位延时使能,关看门狗,内部振荡无时钟输出
*************************************************
* 寄存器定义及RAM分配 *
*************************************************
ERRORLEVEL -302 编译输出结果中不要显示message
cblock 0x20 通用变量定义从该地址开始
W_TEMP 中断服务程序用来临时保存W和STATUS
STATUS_TEMP
FLAGS 程序要使用的状态标志寄存器
PWM_HIGH:2 新的PWM高电平时间,保留两个字节
PWM_LOW:2 新的PWM低电平时间,保留两个字节
PWM_HIGH_CURRENT:2 当前PWM的高电平时间锁存
PWM_LOW_CURRENT:2 当前的PWM低电平时桐耐间锁存
COUNTER AD采样次数计数
adsum:2 16位的AD累加结果,用于平均运算,两个字节
temp:2 用于数学运算的临时变量,两个字节
endc 结束cblock变量定义
count EQU 38H
result EQU 39H
************************************************
I/O引脚初始化 *
以及 A/D 初始化 *
************************************************
GP0 = 模拟电压输局改春入
GP1 = 没有使用
GP2 = 没有使用
GP3 = 只能作为输入,连接10K下拉电阻到地,ICSP烧录会使用该引脚
GP4 = PWM1 输出引脚
GP5 = PWM2 输出引脚
/ *** *** *** *** *** / 代换定义
#define PWM_OUTPUT GPIO,2 GPIO,4
#define LOAD_PWM FLAGS,0
#define CALCULATE_AD FLAGS,1
#define PWM_TICKS .1024 PWM时间片的个数,如果PWM的分辨率是10位,
#define TEST_PWM_HIGH .512 用于测试的50%占空比,高电平时间等于PWM时间片的一半
#define TEST_PWM_LOW PWM_TICKS-TEST_PWM_HIGH 低电平时间等于PWM时间片减高电平时间
#define ISR_DELAY .16 从Timer1溢出到进入中断重新装载Timer1值的延时,
可通过软件模拟来确定该值
#define NUM_AD_SAMPLES .16 AD采样次数
#define AD_TIME_INTERVAL .10 0xFF - (.245) AD时间间隔,10个cycle的循环
/ *** *** *** *** *** / 定义双字节常数减变量的宏
const_input - input = output
sub_const_16 macro const_input, input, output
movlw low const_input W = low 双字节常数 L
movwf temp
movlw high const_input W = high 双字节常数 H
movwf temp+1
movf input,w W = input
subwf temp,w W = temp - W
movwf output output = W
movf input+1,w W = input+1
btfss STATUS,C C = 1 ->
incf input+1,w W = input+1 + 1
subwf temp+1,w W = temp+1 - W
movwf output+1 output+1 = W
endm
/ *** *** *** *** *** / 定义双字节常数加变量的宏
const_input + input = output
add_const_16 macro const_input, input, output
movlw low const_input W = low 双字节常数 L
movwf temp
movlw high const_input W = high 双字节常数 H
movwf temp+1
movf input,w W = input
addwf temp,w W = temp + W
movwf output output = W
movf input+1,w W = input+1
btfsc STATUS,C C = 0 ->
incf input+1,w W = input+1 + 1
addwf temp+1,w W = temp+1 + W
movwf output+1 output+1 = W
endm
/ *** *** *** *** *** / 程序开始
/ *** *** *** *** *** /
org 0000H 芯片复位入口地址0x00
goto MAIN000 主程序
/ *** *** *** *** *** / 中断服务子程序
/ *** *** *** *** *** /
INTCON,T0IF---TMR0 溢出 INTCON,INTF---GP2/INT外部中断
INTCON,GPIF---GP5-GP0 引脚电平发生了变化
PIR1,EEIF---EEPROM 写 *** 作完成 PIR1,ADIF---A/D 转换完成
PIR1,CMIF---比较器输入已改变 PIR1,TMR1IF---TMR1 溢出
org 0004h 中断入口地址0x0004
INTCON00 movwf W_TEMP W_TEMP = W 保存
swapf STATUS,W STATUS_TEMP = STATUS
movwf STATUS_TEMP
bcf STATUS,RP0 选择Bank 0
INTCON02 movlw b'00000100' 把W的第四位置高,其他都是零
xorwf GPIO,F 和GPIO异或,也就是把PWM输出脚的电平反转
判断中断种类
INTCON03 bcf PIR1,TMR1IF 清 T1 中断标志 Timer1 中断
movlw HIGH 3CAFH Timer1 = 50 mS C350H
movwf TMR1H FFFFH - C350H = 3CAFH
movlw LOW 3CAFH
movwf TMR1L
bsf CALCULATE_AD 置位 A/D 转换标志
bsf LOAD_PWM 置位 PWM 标志
INTCON08 swapf STATUS_TEMP,W 恢复STATUS寄存器
movwf STATUS
swapf W_TEMP,F 恢复W寄存器
swapf W_TEMP,W
retfie 从中断返回
/ *** *** *** *** *** / 主程序
/ *** *** *** *** *** /
MAIN000 clrf GPIO 初始化GPIO端口寄存器为零
bsf STATUS, RP0 选择Bank 1
call 0x3FF 读内部振荡出厂校准字,返回值在W寄存器内
movwf OSCCAL 内部振荡器校准
movlw b'11000011' 设置GP<0>为输入,所有其他口为输出
movwf TRISIO
movlw 01h 使能Timer1中断 01h
movwf PIE1
movlw b'00010001' AD采用FOSC/8 时钟,GP2是模拟口,
movwf ANSEL 其他口为数字IO
movlw b'00001000' Timer0设置为使用内部指令周期,无预分频
movwf OPTION_REG
bcf STATUS, RP0 选择Bank0
movlw b'10000001' A/D是右对齐格式,Vdd为参考,GP0作为AD输入口
movwf ADCON0
movlw b'00000111' 关掉内部比较器,让比较器的输入都为数字口
movwf CMCON
movlw 0C0h 使能周边外设中断和全局中断
movwf INTCON
movlw b'00000001' Timer1是1:1预分频,内部时钟源,
movwf T1CON 振荡频率/4,不带门控
movlw .16 AD 次数 = 10
movwf COUNTER
MAIN010 btfss CALCULATE_AD = 1 -> 主循环
goto MAIN010
bcf CALCULATE_AD 清 A/D 转换标志
bsf STATUS,RP0 选择bank1
movf ADRESL,W W = AD L
addwf adsum,F adsum = AD L
btfsc STATUS,C C = 0 ->
incf adsum+1,F adsum+1 = adsum+1 + 1
bcf STATUS,RP0 选择Bank0
movf ADRESH,W W = AD H
addwf adsum+1,F adsum+1 = AD H
bsf ADCON0,GO_DONE 启动 AD 下一次转换
decfsz COUNTER,F 转换 计数器 - 1 = 0 ->
goto MAIN010 循环
movfw adsum
movwf result result = w
CALL LED000
movfw adsum+1
movwf result result = w
CALL LED000
movlw .16 AD 次数 = 10
movwf COUNTER
clrf adsum 清 A/D 累加和 / 平均值 寄存器
clrf adsum+1
goto MAIN010
/ *** *** *** *** *** / 串行输出
LED000 movlw 8 串行输出 8 位 w = 8
movwf count count = w
LED001 bcf TRISIO,4 清零
btfsc result,0 result.7=0 ->
bsf TRISIO,4 0010 0000
bsf TRISIO,5 产生时钟脉冲 GP4 = 1
bcf TRISIO,5 GP4 = 0
RRF result,1 左移获取下一个结果位
decfsz count,1 - 1
goto LED001 <> 0 循环下位
RETURN = 0
/ *** *** *** *** *** /
end 程序结束符
共阳共阴只是你在选COM端时给其高低电平的问题无关大雅我给一段PIC单片机的程序让你参考一下,如果你看懂的话应该能做出来了
#include <pic.h>
#include <math.h>
//此程序实现计时秒表功能,时钟显示范围00.00~99.99秒,分辨度:0.01秒
unsigned char s0,s1,s2,s3;
//定义0.01 秒、0.1 秒、1秒、冲空物10秒计时器
unsigned char s[4];
unsigned char k ,data ,sreg;
unsigned int i;
const table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0XD8,0x80,0x90};
//不带小数点的显示段码表
const table0[10]={0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10};
//带小数点的显示段码表
//TMR0初始化子程序
void tmint()
{
T0CS=0;//TMR0工散液作于定时器方式
PSA=1; //TMR0不用分频
T0IF=0; //清除TMR0的中断标志
T0IE=1; //TMR0中断允许
}
//spi显示初始化子程序
void SPIINIT()
{
PIR1=0;
SSPCON=0x30;
SSPSTAT=0xC0;
//设置SPI的控制方式,允许SSP方式,并且时钟下降沿发送。与"74HC595,当其
//SCLK从低到高跳变时,串行输入寄存器"的特点相对应
TRISC=0xD7; //SDO引脚为输出,SCK引脚为输出
TRISA5=0;//RA5引脚置为输出,输出显示锁存信号
}
//系统其它部分初始化子程序
void initial()
{
TRISB1=0;
TRISB2=0;
TRISB4=1;
TRISB5=1;//设置与键盘有关的各口的输入输出方式
RB1=0;
RB2=0; //建立键盘扫描的初始条件
}
//SPI传输亏升数据子程序
void SPILED(data)
{
SSPBUF=data; //启动发送
do {
;
}while(SSPIF==0);
SSPIF=0;
}
//显示子程序,显示4位数
void dispaly()
{
RA5=0; //准备锁存
for(k=4;k>0;k--)
{
data=s[k-1];
if(k==3) data=table0[data];//第二位需要显示小数点
else data=table[data];
SPILED(data); //发送显示段码
}
for(k=0;k<4;k++)
{
data=0xFF;
SPILED(data); //连续发送4个DARK,使显示好看一些
}
RA5=1; //最后给锁存信号,代表显示任务完成
}
//软件延时子程序
void DELAY()
{
for(i = 3553; --i ;) continue;
}
//键扫描子程序
void KEYSCAN()
{
while(1){
while(1)
{
dispaly(); //调用一次显示子程序
if ((RB5==0)||(RB4==0)) break;
}
DELAY(); //若有键按下,则软件延时
if ((RB5==0)||(RB4==0)) break;//若还有键按下,则终止循环扫描,返回
}
}
//等键松开子程序
void keyrelax()
{
while(1){
dispaly();//调用一次显示子程序
if ((RB5==1)&&(RB4==1)) break;
} //为防止按键过于灵敏,每次等键松开才返回
}
//系统赋值初始化子程序
void inizhi()
{
s0=0x00;
s[0]=s0;
s1=0x00;
s[1]=s1;
s2=0x00;
s[2]=s2;
s3=0x00;
s[3]=s3; //s0=s1=s2=s3=0,并放入显示缓冲数组中
sreg=0x00;//tmr0中断次数寄存器清0
}
//中断服务程序
void interrupt clkint(void)
{
TMR0=0X13; //对TMR0写入一个调整值。因为写入TMR0后接着的
//两个周期不能增量,中断需要3个周期的响应时间,
//以及C语言自动进行现场保护要消耗周期
T0IF=0; //清除中断标志
CLRWDT();
sreg=sreg+1;//中断计数器加1
if(sreg==40)//中断次数为40后,才对S0,S1,S2,S3 *** 作
{
sreg=0;
s0=s0+1;
if(s0==10){
s0=0 ;
s1=s1+1;
if(s1==10){
s1=0 ;
s2=s2+1;
if(s2==10){
s2=0;
s3=s3+1;
if(s3==10) s3=0 ;
}
}
}
}
s[0]=s0;
s[1]=s1;
s[2]=s2;
s[3]=s3;
}
//主程序
main()
{
OPTION=0XFF;
tmint(); //TMR0初始化
SPIINIT();//spi显示初始化
initial(); //系统其它部分初始化
di(); //总中断禁止
while(1) {
inizhi();//系统赋值初始化
KEYSCAN(); //键扫描,直到开始键按下
keyrelax(); //等键松开
ei();//总中断允许
TMR0=0X08;
KEYSCAN(); //键扫描直到停止键按下,在键扫描时有显示
keyrelax() ; //等键松开
di();//总中断禁止
KEYSCAN(); //键扫描到清0键按下,在键扫描时有显示
keyrelax() ; //等键松开
}
}
#include <pic.h>#define uchar unsigned char
unsigned char RC_data
int hz=0
void usart_init()
{
TRISC6=0//RC6:TX为发送口
TRISC7=1/扮中/RC7:RX为接收口
TXSTA=0x24//使能发送,高波特率
RCSTA=0x90//串口使能,连续接收
SPBRG=0x19//设置波特率9600
TRISD=0x00//D口为输出
PORTD=0xF0//D口清零
// 中断设置
PIR1=0X00
PIE1=0X00
RCIE=1
TXIE=0
INTCON=0X00
PEIE=1
GIE=1
}
void interrupt uart()
{
if(1==RCIF)
{
RCIF=0
RC_data=RCREG
TXREG=RC_data
}
if(1==TXIF)
{
TXIF=0
PORTD=0X0F
}
}
main()
{
usart_init() //初始化
while(1)
}
单片机编程,本身不区分RS232与RS485。如果厅旅山你需镇大要RS485通讯,可以用MAX488芯片实现485通讯。再用个RS232-485转换器,接到计算机上,用个串口调试工具就能用了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)