赞
踩
写在前面的话:
带开机音乐,速度、进度和行驶方向显示的出租出计费系统设计
模拟出租车系统的功能,除了基本起价、里程计算、费用显示等功能外,增加了开机音乐(可选)、里程及费用锁存、速度可调、直流电机转速可调、行驶方向显示、8*8 LED点阵闪烁频率可调、1km内里程显示等功能。
具体要求如下:
TC0工作于方式3方波发生器模式,用于将250kHz信号分频到较低频率。
TC1工作于方式2分频器模式,输出占空比可调的PWM信号。一方面用作中断触发输入,调用中断服务程序的执行;另一方面,经过非门作为直流电机的输入信号,通过占空比的调整改变直流电机的转速。
TC2工作于方式3方波发生器模式,用于改变计数初值N产生特定频率的信号,实现音乐播放的功能。
电位器控制出租车速度。
通过ADC0809读取速度,对出租车里程、费用进行控制。
六位共阴极LED数码管显示里程和费用。
六位数码管的高2位显示里程数(XX千米),低3位显示费用(显示XX.X元),两者之间的数码管显示“-”作为分隔。
出租车的速度大小同时由直流电机的转速和8*8 LED点阵的闪烁频率表示。
系统初始状态的设定。
里程数00(km),低3位显示起步价(设置为10元)。2km内价格不变,超过2km,按每公里1.2元计价。
通过5个开关实现系统控制:
通过3个LED灯精确显示1km内的里程。
1km内的进度由3个LED灯显示。全灭、一个灯亮、两个灯亮、三个灯亮分别表明出租出位于1km内的[0m, 250m]、[250m, 500m]、[500m, 750m]、[750m, 1000m]区间。
;---------------------------------------------------------- ; 出租车系统设计 ;---------------------------------------------------------- .model small .386 data segment ;---------------------设置各端口地址------------------- ;8254基址值 --> 计时器 i8254_0 equ 200H ;8255端口地址 --> 中间接口 i8255_a equ 210h ;8255A口,初始化PA为输出 i8255_b equ 211h ;8255B口,初始化PB为输入 i8255_c equ 212h ;8255C口 i8255_k equ 213h ;8255控制口 AD_IO equ 220h led_io equ 240h ;LED灯地址 ;---------------------设置led编码------------------ ledcode_1 db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,67h ;不带. --> 指小数点 ledcode_2 db 0bfh,86h,0dbh,0cfh,0e6h,0edh,0fdh,87h,0ffh,0e7h ;带. --> 指小数点 ledcode_3 db 40h ;字符"-" ;--------------------设置变量信息------------------ count_km db 00h ;转换的路程(km) price dw 100 ;起步价定为100角(10元) N db 0 clear_flag db 0 ;为1则表示清零 temp db 0 ;暂存clear_flag的状态 km_flag db 0 ;为7则表示已达到1km,此时更新km和price,并将km_flag清零 ;8*8点阵 updown_flag db 0 led3 db 08h,0ch,0eh,7fh,7fh,0eh,0ch,08h led4 db 08h,18h,38h,7fh,7fh,38h,18h,08h count dw 00h bz dw ? ShowProgress_flag db 0 progress_0 db 00000010b ;音乐模块 sound_flag db 0 mus_freq dw 262,262,262,196 dw 330,330,330,262 dw 262,330,392,392 dw 349,330,294 dw 294,330,349,349 dw 330,294,330,262 dw 262,330,294,196 dw 247,294,262,-1 mus_time dw 3 dup(12,12,25,25),12,12,50 dw 3 dup(12,12,25,25),12,12,50 data ends ssg segment stack dw 100 dup(0) ssg ends code segment assume cs:code,ds:data,ss:ssg main proc far mov ax, data mov ds, ax ;--------------------各端口初始化---------------- cli ;关中断进行初始化 call clock ;时钟设置 ;--------------------初始化8255-------------------- mov dx,i8255_k mov al,88h ;8255控制字 out dx,al ;8255为模式0,PA、PB为输出,PC高位为输入,低位为输出 ;--------------设置386EX主8259中断屏蔽字------------- in al,21h and al,11010111b ;开放IR3、IR5中断,IR3是里程清零,IR5是正常计数740的产生的中断 out 21h,al ;---------------------设置中断向量表---------------------- ;设置IR5 push ds mov ax, 0 mov ds, ax ;ds指向00000H,为中断向量表的地址范围的起始地址 ;中断向量表的IP值 lea ax, cs:int_proc1 ;ax为中断程序入口地址的偏移地址IP mov si, 35h ;类型码35h add si, si ;类型码*4得到中断向量 add si, si ;找到中断向量表中终端类型码35h对应的位置的起始地址 mov ds:[si], ax ;将中断服务程序的IP放到中断类型码的对应位置 ;中断向量表的CS值 push cs pop ax ;ax <-- 中断服务程序的段地址cs mov ds:[si+2], ax ;将中断服务程序的cs放到中断类型码的对应位置 pop ds ;---------------------音乐模块--------------------- ;使得直流电机模拟齿轮转动 mov al, 255 mov dx, i8254_0 add dx, 1 out dx, al call read_state cmp sound_flag, 01000000b jne next_test_music ;输出音乐 ;获得频率和时间的首地址 lea si, mus_freq lea di, mus_time play: mov dx, [si] cmp dx, -1 ;频率为-1时结束播放 je end_play call sound ;sound函数用于演奏一个字符 add si, 2 ;指向下一个数据 add di, 2 call read_state ;允许在歌曲中间打断歌曲,下次歌曲依旧从头播放 cmp sound_flag, 01000000b jne sound_exit jmp play end_play: mov ax, 2 mov dx, i8254_0 add dx, 2 out dx, al ;先送低8位到计数器,dx是8253芯片通道2的端口地址 mov al, ah out dx, al ;后送高8位计数器 next_test_music: sti ;开中断 ;---------------------等待中断---------------------- LLL: call machine ;重复刷新直流电机 call read_state ;读取状态 ;判断清零标志,clear_flag不为0则初始化count_km和price cmp clear_flag, 00010000b jne next2 call clear next2: cli ;关中断执行disp call disp ;重复刷新LED显示 sti ;执行disp结束,开中断 jmp LLL main endp ;---------------------中断时钟设置----------------- ;子函数功能:将1MHz信号进行10000分频,得到100Hz的方波 ;芯片:8254,计数器0,方式3(方波方式),读写先低后高,二进制计数 ;输出:out0口得到100Hz的信号,用于统计路程 clock proc ;计数器 0 的 CW 和 N mov dx, i8254_0 add dx, 3 ;指向控制口 mov al, 00110110b ;计数器0,方式3(方波方式),读写先低后高,二进制计数 out dx, al mov dx, i8254_0 ;指向计数器0 mov ax, 1875 ;赋初值N out dx, al mov al, ah out dx, al ;计数器 1 的 CW 和 N mov dx, i8254_0 ;向8254写控制字 add dx, 3 mov al, 01010100b ;计数器1,方式2(分频器),只写低 out dx, al mov dx, i8254_0 add dx, 1 ;指向计数器1 mov al, 2 ;在N属于[0,12]下,使N初始化为2 out dx, al ;计数器 2 的 CW mov al, 10110110b ;8254初始化TC2,读写16位,方式3方波模式 mov dx,i8254_0 add dx, 3 out dx,al ret clock endp ;-----------------AD转换并计算速度函数--------------- AD_transfer proc mov dx, AD_IO ;ADC启动转换地址 out dx, al ;启动ADC mov dx, AD_IO ;获取ADC EOC状态地址 add dx, 2 L1: in al, dx test al, 01h ;测试EOC是否为1 jz L1 mov dx, AD_IO ;读数据地址 inc dx in al, dx mov ah, 0 mov cl, 21 div cl ;获得2-12档,2档最快,12档停止 mov N, al ret AD_transfer endp ;---------------------进度显示子函数------------------- progress proc push ax mov al, progress_0 ;读取progress_0到al dec al ;得到要显示的进度 mov dx,i8255_c out dx, al ;将al输出到下C口 rol progress_0, 1 ;progress_0循环左移,为下一次做准备 cmp progress_0, 00010000b ;1从第四位左移到高四位,则将progress_0还原为初始值 jb next_progress mov progress_0, 00000001b next_progress: pop ax ret progress endp ;----------------中断服务子程序IS5--------------- int_proc1 proc far push ax push dx call AD_transfer ;读取电位器对应的N call disp88 ;调用点阵显示函数 add km_flag, 1 cmp km_flag, 4 jne no_update ;km_flag为8时,表示已经运行1KM,需更新count_km和price ;更新km和price call calculate_km call calculate_price mov km_flag, 0 ;更新完毕,对km_flag清0 no_update: ;-------------------------显示进度版本修改代码------------------------- call progress ;更新km进度 ;-------------------------显示进度版本修改代码------------------------- continue_int_proc1: ;对计数器1重新赋初值 mov dx, i8254_0 add dx, 1 ;指向计数器1 cmp N, 2 jae next_int_proc1 mov N, 2 ;设置最快速度,高低电平至少各0.5秒 next_int_proc1: mov al, N ;赋值新的N值 out dx, al ;发送中断结束命令 EOI mov al,20h out 20h,al ;(向386EX主8259) pop dx pop ax sti ;开中断 iret int_proc1 endp ;sound函数:演奏一个音符 ;入口参数:si - 要演奏的音符的频率的地址 ; di - 要演奏的音符的音长的地址 sound proc push ax push dx push cx ;{dx, ax}作为被除数,我认为{dx, ax}是TC2的输入频率 ;应该是基于一个公式:输入频率250kHz = 分频数ax(TC2的N)* 声音频率(分频后的频率) ;call read_state ;允许在歌曲中间打断歌曲,下次歌曲依旧从头播放 ;cmp sound_flag, 01000000b ;jne sound_exit mov dx,0003h ;TC2输入频率为250kHz mov ax,0d090h ;[si]作为除数 div word ptr [si] ;计算分频值,赋给ax。[si]中存放声音的频率值。 ;将ax作为TC2的N,输出到TC2端口 mov dx, i8254_0 add dx, 2 out dx, al ;先送低8位到计数器,dx是8253芯片通道2的端口地址 mov al, ah out dx, al ;后送高8位计数器 mov dx, [di] ;保持[di]时长 wait11: mov cx, 14000 delay_sound: nop loop delay_sound dec dx jnz wait11 pop cx pop dx pop ax sound_exit: ret sound endp ;-------------------显示函数------------------ disp proc push bx push dx ;km显示 ;清除鬼影 mov al, 0 mov dx, led_io out dx, al mov al, 000000b inc dx out dx, al call delay lea bx, ledcode_1 mov al, count_km mov ah, 0 mov cl, 10 ;截取十位 div cl mov ah, 0 div cl mov al, ah mov ah, 0 add bx, ax mov al, [bx] ;取得要显示的数据 mov dx, led_io ;获取显示的地址 out dx, al ;输出数据 mov al, 100000b ;指明要点亮的位为第一位 inc dx ;地址加1 out dx, al call delay ;清除鬼影 mov al, 0 mov dx, led_io out dx, al mov al, 000000b inc dx out dx, al call delay lea bx, ledcode_1 mov al, count_km mov ah, 0 mov cl, 10 ;截取个位 div cl mov al, ah mov ah, 0 add bx, ax mov al, [bx] mov dx, led_io out dx, al mov al, 010000b inc dx out dx, al call delay ;清除鬼影 mov al, 0 mov dx, led_io out dx, al mov al, 000000b inc dx out dx, al call delay ;显示"-"字符 mov al, ledcode_3 mov dx, led_io out dx, al mov al, 001000b inc dx out dx, al call delay ;清除鬼影 mov al, 0 mov dx, led_io out dx, al mov al, 000000b inc dx out dx, al call delay ;显示价格 lea bx, ledcode_1 mov ax, price mov cl, 10 ;截取百位 div cl mov ah, 0 div cl mov ah, 0 div cl mov al, ah mov ah, 0 add bx, ax mov al, [bx] mov dx, led_io out dx, al mov al, 000100b inc dx out dx, al call delay ;清除鬼影 mov al, 0 mov dx, led_io out dx, al mov al, 000000b inc dx out dx, al call delay lea bx, ledcode_2 ;带小数点 mov ax, price mov cl, 10 ;截取十位 div cl mov ah, 0 div cl mov al, ah mov ah, 0 add bx, ax mov al, [bx] mov dx, led_io out dx, al mov al, 000010b inc dx out dx, al call delay ;清除鬼影 mov al, 0 mov dx, led_io out dx, al mov al, 000000b inc dx out dx, al call delay lea bx, ledcode_1 mov ax, price mov cl, 10 ;截取个位 div cl mov al, ah mov ah, 0 add bx, ax mov al, [bx] mov dx, led_io out dx, al mov al, 000001b inc dx out dx, al call delay ;清除鬼影 mov al, 0 mov dx, led_io out dx, al mov al, 000000b inc dx out dx, al call delay pop dx pop bx ret disp endp ;-----------------里程计算函数------------------ ;子函数功能:该程序在IR5被响应时调用,表示740个clk计数完毕,对应公里数加1 calculate_km proc push ax mov al, 1 add count_km, al cmp count_km, 99 jb no_clear mov count_km, 0 mov price, 100 no_clear: pop ax ret calculate_km endp ;-----------------价格计算函数------------------ calculate_price proc mov al, count_km cmp al, 2 ;2km为起始距离 ja bigger mov price, 100 ;起始价为10 jmp exit1 bigger: sub al, 2 mov dl, 12 mul dl add ax, 100 mov price, ax ;存储结果,用于显示 exit1: ret calculate_price endp ;----------------状态读取并显示函数--------------- read_state proc ;---------------------测试代码2:在测试代码一上,查看是否能正常读入数据---------------------- mov dx, i8255_c in al, dx mov clear_flag, al ;读取clear_flag状态,为D4位 and clear_flag, 00010000b mov dx, i8255_c in al, dx mov updown_flag, al ;读取updown_flag状态,为D5位 and updown_flag, 00100000b mov dx, i8255_c in al, dx mov sound_flag, al ;读取sound_flag状态,为D4位 and sound_flag, 01000000b ;---------------------测试代码2:在测试代码一上,查看是否能正常读入数据------------------- ret read_state endp ;-----------------里程清零函数------------------ ;子函数功能:当clear_flag为1时被调用,清零count_km clear proc mov count_km, 0 mov price, 100 ret clear endp ;-------------------直流电机函数------------------ ;原理,通过方式2的分频,导致占空比不同,N越大,占空比越小(需经过非门) ;test1修改版本,经dosbox测试正确,开发板待检验 machine proc mov al, N mov ah, 0 mov dx, i8254_0 add dx, 1 ;指向TC1 out dx, al ;N为2~12,2最快,12停止 ret machine endp ;---------------8*8点阵显示--------------- disp88 proc push cx mov di, offset led3 ;设di为字形码缓冲区指针(指向首地址), LED3为上升箭头 call read_state cmp updown_flag, 00100000b je next_disp88 mov di, offset led4 ;设di为字形码缓冲区指针(指向首地址), LED3为下降箭头 next_disp88: mov cx, 0005h ;点阵扫描次数 call disp0 ;调用扫描子程序 pop cx ret disp88 endp ;--------------点阵子函数-------------- disp0 proc push bx push ax push dx loop5: mov count, 0000h ;计数器初始=0 mov bh, 01h ;产生最高位扫描码 mov al, 0 ;扫描码消失(熄灭) ;mov dx, 202h ;关闭扫描信号 -->8255地址,待改 mov dx, i8255_b ;关闭扫描信号 -->PA为扫描信号 out dx, al ;LED灯熄灭 lll0: mov byte ptr bz,bh push di add di,count mov bl,byte ptr[di] pop di mov al,bl ;mov dx,201h ;8255b控制行 mov dx,i8255_a ;8255b控制行 out dx,al mov al,byte ptr bz mov dx,i8255_b ;8255c控制列 显示bz列 out dx,al inc count push cx mov cx,20h ;延迟一段时间 delay0: loop delay0 pop cx mov al,0 ;mov dx,202h ;关闭扫描信号 mov dx, i8255_b ;关闭扫描信号 out dx,al mov bh,byte ptr bz shl bh,1 ;bh指向下一位 jnz lll0 ;8列都扫描完结束 loop loop5 pop dx pop ax pop bx ret disp0 endp ;------------------延时函数------------------ delay proc push cx mov cx, 30 X1: loop X1 pop cx ret delay endp code ends end main
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。