joyrus 发表于 2012-6-26 11:44:56

我的第三个单片机开源项目——通过PIC单片机的SUART与PC通信显示采样数据

本帖最后由 joyrus 于 2012-7-6 18:40 编辑

开源项目名称:通过PIC单片机的SUART与PC通信显示采样数据

设计目的:用于实现对单片机采样的数据进行保存并通过SUART模块传输到PC的串行端口。



正在做准备工作,先学习有关SUART的相关知识和PC端软件的设计,这可能需要不少的时间。准备首先完成MCU通过SUART模块传输到PC并通过超级终端来显示,随后在设计PC端的专门程序。


对程序作了修改增加了ADC采样,数据平滑处理。通过RS232收到数据,通过调整ADC采样电位器可以看到电脑上显示出不同的字符。

joyrus 发表于 2012-6-30 20:35:55

先通过对张明峰先生撰写的《PIC单片机入门与实战》的阅读和学习,摘录了其中部分的代码,作为这次我的开源项目的开始。

以下代码基本上和书籍上的内容一致,实现了向串口持续发送1234以及回车和换行字符,通过超级终端可以收到,本人对部分代码做了一些替换,以方便自己的理解。

;**********************************************************************
;程序功能说明
;本程序通过单片机USART端口与PC串口通信,程序主体摘录自张明峰先生撰写的《PIC单片机入门与实战》
;本人联系方法:沈毅;joyrus@163.net,www.joyrus.com,QQ:15953321
;**********************************************************************

; 程序定义部分

#include <p16f877A.inc>; 选择的单片机型号

; __CONFIG 单片机配置


;***** VARIABLE DEFINITIONS
fsr_temp EQU 0x7C; 因为在程序中使用间接寻址故在中断中需要保护FSR寄存器
w_tempEQU 0x7D; variable used for context saving
status_temp EQU 0x7E; variable used for context saving
pclath_temp EQU 0x7F; variable used for context saving   

   cblock 0x20
tx_buff:8                     ; 定义发送数据缓冲区
tx_point                      ; 发送数据指针
tx_count                     ; 发送数据计数器
   endc

#define TX_IE PIE1,TXIE         ;定义一些中断功能寄存器功能位的替换符号方便代码理解
#define TX_IF PIR1,TXIF
#define PE_IE INTCON,PEIE
#define G_IE INTCON,GIE

joyrus 发表于 2012-6-30 20:39:15

中断处理程序,发送数据


ORG   0x000             ; processor reset vector
   nop                            ; nop required for icd
   goto    main            ; go to beginning of program

ORG   0x004               ; interrupt vector location

movwf   w_temp            ; save off current W register contents
movf STATUS,w            ; move status register into W register
movwf status_temp       ; save off contents of STATUS register
movf PCLATH,w            ; move pclath register into w register
movwf pclath_temp       ; save off contents of PCLATH register
movf FSR,w                  ; 保护FSR
movwf fsr_temp

   ;判断是否串行发送中断
   bankselPIE1
   btfssTX_IE
   gotoOther_int
   bankselPIR1
   btfssTX_IF
   gotoOther_int
   ;判断完成,间接寻址取数据
   movlwtx_buff
   movwfFSR
   movftx_point,w
   addwfFSR,f
   movfINDF,w
   ;发生数据
   movwfTXREG
   ;偏移指针等准备发送下一个数据
   incftx_point
   decfsztx_count,f   ;缓冲区还有数据没有发送完毕
                                       ;保持打开TXIE中断
                                       ;一个字节发送完后产生中断继续发送后续数据
   gotoEnd_int
   ;缓冲区数据全部发送完毕,完成清理工作
   bankselPIE1
   bcf   TX_IE
   ;bank0
   ;***********************
   bankselSTATUS         ; 返回Bank0

Other_int
   
End_int

movf fsr_temp,w             ; 恢复FSR寄存器
movwf FSR   
movf pclath_temp,w      ; retrieve copy of PCLATH register
movwf PCLATH                ; restore pre-isr PCLATH register contents
movf    status_temp,w   ; retrieve copy of STATUS register
movwf STATUS               ; restore pre-isr STATUS register contents
swapf   w_temp,f
swapf   w_temp,w            ; restore pre-isr W register contents
retfie                               ; return from interrupt

joyrus 发表于 2012-6-30 20:42:23

主程序部分

main
   ;初始化
   ;Bank1 定义串行通信的相关寄存器
   ;*********************
   bankselTXSTA
   movlwb'00100100'
   movwfTXSTA
   movlw.25                  ; 定义9600bps
   movwfSPBRG
   clrfPIE1                     ; 关闭中断
   ;Bank0
   ;*********************
   bankselRCSTA
   movlwb'10000000'
   movwfRCSTA
   clrftx_count                     
   clrfINTCON
   bsf   PE_IE                      ; 打开中断   
   bsf   G_IE                        ; 打开中断

ADC_doing
   callSend_data               ; 调用数据发送子程序
   goto$-1                         ; 重复循环发送数据

joyrus 发表于 2012-6-30 20:43:49

发送数据子程序

;===================================
;数据发送子程序
;===================================
Send_data
   ;Bank0
   ;**********************
   bankselSTATUS   ;选择Bank0
   movftx_count,w
   skpz                      ;数据是否发送完
   return                  ;还有数据未发送完返回
   ;装载新数据
   movlw'1'
   movwftx_buff+0
   movlw'2'
   movwftx_buff+1
   movlw'3'
   movwftx_buff+2
   movlw'4'
   movwftx_buff+3
   movlw0x0B
   movwftx_buff+4
   movlw0x0A
   movwftx_buff+5      ;完成数据装载
   movlw.6
   movwftx_count       ;设定发送数据的数量
   clrftx_point             ;复位偏移指针
   ;Bank1
   ;***********************
   bankselPIE1
   bsf   TX_IE               ;开启发送中断,立即发送数据
   ;Bank0
   ;***********************
   bankselSTATUS       ; 返回Bank0
   return
;=====================================
   
END                     ; directive 'end of program'

joyrus 发表于 2012-6-30 20:47:53

通过这个发送程序,我可以借此来调试PC段的接受软件,本人正在使用C语言编写一个简单的串口数据接收程序来接受数据并转换成需要的方式来显示,比如通过ADC采样0-5V的电压,然后通过串口发送数据到PC上显示出电压,这就相当于一个0-5V的简易数字电压表。

joyrus 发表于 2012-7-6 18:33:53

在继续学习C语言的同时,修改了上面的最基本的数据传输程序,加入了ADC采样,然后对数据取平均值,最后放到结果寄存器中,随时等待中断调用数据并发送到RS232端口。

程序如下:中断发送程序没有什么变化

;**********************************************************************
;程序功能说明
;本程序通过单片机USART端口与PC串口通信
;本程序有很大的优化空间和存在安全漏洞,这个程序只是本人的学习过程,和大家共同探讨的载体
;本人联系方法:沈毅;joyrus@163.net,www.joyrus.com,QQ:15953321
;**********************************************************************
listp=16f877A ; list directive to define processor
#include <p16f877A.inc> ; processor specific variable definitions

__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.

;***** VARIABLE DEFINITIONS
fsr_temp EQU 0x7C       ; variable used for context saving
w_tempEQU 0x7D       ; variable used for context saving
status_temp EQU 0x7E; variable used for context saving
pclath_temp EQU 0x7F   ; variable used for context saving   
   cblock 0x20
tx_buff:8
tx_point
tx_count
ad_data_buff: 8            ;采样数据缓冲区
ad_data_point            ;采样数据缓冲区偏移指针
ad_data_L                  ;采样数据平滑处理单元低8位
ad_data_H                  ;采样数据平滑处理单元高8位
ad_result_L                ;最终采样数据低8位
ad_result_H                ;最终采样数据高8位
   endc
#define TX_IE PIE1,TXIE
#define TX_IF PIR1,TXIF
#define PE_IE INTCON,PEIE
#define G_IE INTCON,GIE
;**********************************************************************
ORG   0x000             ; processor reset vector
nop                            ; nop required for icd
   goto    main            ; go to beginning of program

ORG   0x004             ; interrupt vector location
movwf   w_temp            ; save off current W register contents
movf STATUS,w          ; move status register into W register
movwf status_temp       ; save off contents of STATUS register
movf PCLATH,w          ; move pclath register into w register
movwf pclath_temp       ; save off contents of PCLATH register
movf FSR,w
movwf fsr_temp   
   ;Bank1 判断是否串行发送
   ;**********************
   bankselPIE1
   btfssTX_IE
   gotoOther_int
   bankselPIR1
   btfssTX_IF
   gotoOther_int
   ;判断完成,间接寻址取数据
   movlwtx_buff
   movwfFSR
   movftx_point,w
   addwfFSR,f
   movfINDF,w
   ;发送数据
   movwfTXREG
   ;偏移指针等准备发送下一个数据
   incftx_point
   decfsztx_count,f          ;缓冲区还有数据没有发送完毕
                                       ;保持打开TXIE中断
                                       ;一个字节发送完后产生中断继续发送后续数据
   gotoEnd_int
   ;缓冲区数据全部发送完毕,完成清理工作
   bankselPIE1
   bcf   TX_IE
   ;bank0
   ;***********************
   bankselSTATUS
Other_int
   
End_int
movf fsr_temp,w
movwf FSR   
movf pclath_temp,w         ; retrieve copy of PCLATH register
movwf PCLATH               ; restore pre-isr PCLATH register contents
movf    status_temp,w   ; retrieve copy of STATUS register
movwf STATUS               ; restore pre-isr STATUS register contents
swapf   w_temp,f
swapf   w_temp,w          ; restore pre-isr W register contents
retfie                           ; return from interrupt

joyrus 发表于 2012-7-6 18:37:57

主程序部分变化比较大

加入了ADC采样,数据平滑处理等

main
   ;初始化
   ;Bank1 初始化USART
   ;*********************
   bankselTXSTA
   movlwb'00100100'
   movwfTXSTA
   movlw.25
   movwfSPBRG
   clrfPIE1
   ;Bank1 初始化ADC端口
   ;***************
   movlwb'0000000'
   movwfADCON1
   ;Bank0 初始化USART
   ;*********************
   bankselRCSTA
   movlwb'10000000'
   movwfRCSTA
   clrftx_count
   clrfINTCON
   bsf   PE_IE
   bsf   G_IE
   ;Bank0 初始化ADC端口
   ;****************
   movlwb'00000001'
   movwfADCON0
   ;clrfad_data_point       ;复位ADC数据缓冲区指针
Loop
   callADC_doing             ;调用子程序处理
   callADC_average          ;调用子程序处理
   callADC_send               ;调用子程序处理
   gotoLoop

joyrus 发表于 2012-7-6 18:39:04

三个子程序:

;===================================
;ADC数据发送子程序
;===================================
ADC_send
   ;Bank0
   ;**********************
   bankselSTATUS
   movftx_count,w
   skpz                      ;数据是否发送完
   return                  ;还有数据未发送完返回
   ;装载新数据
   movfad_result_L,w
   movwftx_buff+0
   ;movlw'2'
   movwftx_buff+1
   ;movlw'3'
   movwftx_buff+2
   ;movlw'4'
   movwftx_buff+3
   movlw0x0B
   movwftx_buff+4
   movlw0x0A
   movwftx_buff+5      ;完成数据装载
   movlw.6
   movwftx_count       ;设定发送数据的数量
   clrftx_point       ;复位偏移指针
   ;Bank1
   ;***********************
   bankselPIE1
   bsf   TX_IE          ;开启发送中断,立即发送数据
   ;Bank0
   ;***********************
   bankselSTATUS
   return
;=====================================
;===================================
;ADC转换子程序
;===================================
ADC_doing
   ;Bank0
   ;**********************
   bankselSTATUS
   movlw0x08
   movwfad_data_point   ;设置位移指针
   ;开始采样
   bsf   ADCON0,GO         ;开始ADC
   btfscADCON0,GO         ;ADC转换是否结束
   goto$-1                      ;等待ADC结束
   ;保存ADC结果
   movlwad_data_buff-1    ;取ADC数据缓冲区首地址
   movwfFSR                  ;FSR相对寻址
   movfad_data_point,w   ;取相对位移指针
   addwfFSR,f                  ;相对地址+位移指针
   movfADRESH,w             ;取ADC转换结果
   movwfINDF                   ;放入ADC转换结果
   decfszad_data_point,f   ;指针位移-1指向下一个缓冲单元
   goto$-.9                     ;ad_data_point不等于0则继续转换
   return
;=====================================
;===================================
;ADC数据平滑处理
;===================================
ADC_average
   ;Bank0
   ;**********************
   bankselSTATUS
   movlw0x08
   movwfad_data_point   ;设置位移指针
   clrfad_data_L                ;累加单元清空
   clrfad_data_H         
   ;开始累加
   movlwad_data_buff-1    ;取ADC数据缓冲区首地址
   movwfFSR                     ;FSR相对寻址
   movfad_data_point,w   ;取相对位移指针
   addwfFSR,f                  ;相对地址+位移指针
   movfINDF,w               ;取数据到w
   addwfad_data_L,f         ;进行累加
   skpnc                           ;是否有进位
   incfad_data_H,f             ;有进位高位加1
   decfszad_data_point,f   ;指针位移-1指向下一个缓冲单元
   goto$-.9                     ;ad_data_point不等于0则继续累加
   ;累加完成求平均/除8右移3次
   bcf   STATUS,C
   rrf   ad_data_H,f
   rrf   ad_data_L,f
   bcf   STATUS,C
   rrf   ad_data_H,f
   rrf   ad_data_L,f
   bcf   STATUS,C
   rrf   ad_data_H,f
   rrf   ad_data_L,f
   ;关中断送最终结果   
   bcf   G_IE            ;关中断
   movfad_data_L,w
   movwfad_result_L
   movfad_data_H,w
   movwfad_result_H
   bsf   G_IE            ;开中断
   return
;=====================================
END                     ; directive 'end of program'
页: [1]
查看完整版本: 我的第三个单片机开源项目——通过PIC单片机的SUART与PC通信显示采样数据