目录
第一部分、前言
1、闲话
还是一样,这个设计也是我们《SOPC技术及应用》课程结束的期末作业。我自己的是老师题库里的第五题、驱动AD9854这个模块《【NiosII训练】第一篇、FPGA驱动AD9854基础篇:https://blog.csdn.net/Learning1232/article/details/111193587》,想回去看的铁子们可以回去看。
这一题是我们班同学的,报酬是给我买零食,然后,我就答应了。。。。效果如下:
第二部分、题目要求
1、图片
2、文字描述
使用FPGA调成功18b20温度传感器,并能够将温度实时显示在lcd上,要求只有当某个按键按一下的时候lcd上的温度才会变一下,能够通过其他按键改变温度的阈值。当温度超过阈值时,蜂鸣器会叫。提示,ac620上的蜂鸣器时无源的,最好通过pwm核驱动蜂鸣器叫,或者使用ucosii的某个线程提供pwm信号。
3、题目分析
看了题目要求最主要的就是DS18B20的驱动代码的移植,这是最麻烦的部分。
然而DS18B20我相信大家都玩过,单总线通信方式和DHT11一样,所以在软核里面添加一个双向的PIO核,这么一想是不是简单了很多。
然后还有一个就是按键消抖。
第三部分、工程代码
1、软核的搭建
还是基于小梅哥FPGA的LCD9341的例程修改,在原有的工程上面多添加一个双向的位宽为1位PIO核。
2、顶层文件的代码
module AC620_GHRD(
input wire clk, // clk.clk
input wire reset_n, // reset.reset_n
output wire lcd_rst, // lcd_rst.export
output wire lcd_rd_n, // lcd_rd.export
output wire lcd_bl, // lcd_bl.export
output wire lcd_wr_n, // lcd_wr.export
output wire lcd_rs, // lcd_rs.export
output wire lcd_cs_n, // lcd_cs.export
inout wire [15:0] lcd_data, // lcd_db.export
output wire sdram_clk, // sdram_clk.clk
output wire [11:0] sdram_addr, // sdram.addr
output wire [1:0] sdram_ba, // .ba
output wire sdram_cas_n, // .cas_n
output wire sdram_cke, // .cke
output wire sdram_cs_n, // .cs_n
inout wire [15:0] sdram_dq, // .dq
output wire [1:0] sdram_dqm, // .dqm
output wire sdram_ras_n, // .ras_n
output wire sdram_we_n, // .we_n
input wire uart_0_rxd, // uart_0.rxd
output wire uart_0_txd, // .txd
output wire epcs_dclk, // epcs.dclk
output wire epcs_sce, // .sce
output wire epcs_sdo, // .sdo
input wire epcs_data0, // .data0
inout wire ds18b20,//温度传感器
output wire [3:0] led, //led
input wire s0,//按键
input wire s1,
output wire buzzer//外置蜂鸣器管脚
);
mysystem u0 (
.clk_clk (clk), // clk.clk
.reset_reset_n (reset_n), // reset.reset_n
.uart_0_rxd (uart_0_rxd), // uart_0.rxd
.uart_0_txd (uart_0_txd), // .txd
.epcs_dclk (epcs_dclk), // epcs.dclk
.epcs_sce (epcs_sce), // .sce
.epcs_sdo (epcs_sdo), // .sdo
.epcs_data0 (epcs_data0), //
.lcd_rst_export (lcd_rst), // lcd_rst.export
.lcd_bl_export (lcd_bl), // lcd_bl.export
.lcd_wr_n (lcd_wr_n), // lcd.wr_n
.lcd_rd_n (lcd_rd_n), // .rd_n
.lcd_data (lcd_data), // .data
.lcd_rs (lcd_rs), // .rs
.lcd_cs_n (lcd_cs_n), //
.sdram_clk_clk (sdram_clk), // sdram_clk.clk
.altpll_0_phasedone_conduit_export (), // altpll_0_phasedone_conduit.export
.altpll_0_locked_conduit_export (), // altpll_0_locked_conduit.export
.altpll_0_areset_conduit_export (), // altpll_0_areset_conduit.export
.sdram_addr (sdram_addr), // sdram.addr
.sdram_ba (sdram_ba), // .ba
.sdram_cas_n (sdram_cas_n), // .cas_n
.sdram_cke (sdram_cke), // .cke
.sdram_cs_n (sdram_cs_n), // .cs_n
.sdram_dq (sdram_dq), // .dq
.sdram_dqm (sdram_dqm), // .dqm
.sdram_ras_n (sdram_ras_n), // .ras_n
.sdram_we_n (sdram_we_n), // .we_n
.ds18b20_export (ds18b20), // ds18b20.export
.buzzer_export (buzzer), // buzzer.export
.led_export (led), // led.export
.s0_export (s0), // s0.export
.s1_export (s1) // s1.export
);
3、Ecplise代码
DS18B20.c文件
/*
* ds18b20.c
*
* Created on: 2020年12月4日
* Author: dpt
*/
#include "ds18b20.h"
//DS18B20芯片初始化
alt_u8 Init_DS18B20(void)
{
alt_u8 initflag = 0;
IOWR_ALTERA_AVALON_PIO_DIRECTION(DS18B20_BASE, 1);//方向为输出
IOWR_ALTERA_AVALON_PIO_DATA(DS18B20_BASE, 0);
usleep(550);
IOWR_ALTERA_AVALON_PIO_DATA(DS18B20_BASE, 1);
usleep(40);
IOWR_ALTERA_AVALON_PIO_DIRECTION(DS18B20_BASE, 0);//方向为输入
initflag = IORD_ALTERA_AVALON_PIO_DATA(DS18B20_BASE);
usleep(100);
return initflag; //应答信号为低电平,表示复位成功
}
//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
IOWR_ALTERA_AVALON_PIO_DIRECTION(DS18B20_BASE, 1);//方向为输出
IOWR_ALTERA_AVALON_PIO_DATA(DS18B20_BASE, 0);
usleep(10);
IOWR_ALTERA_AVALON_PIO_DATA(DS18B20_BASE, dat&0x01);
usleep(30);
IOWR_ALTERA_AVALON_PIO_DATA(DS18B20_BASE, 1);
dat >>= 1; //发送下一个数据位
}
}
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
IOWR_ALTERA_AVALON_PIO_DIRECTION(DS18B20_BASE, 1);//方向为输出
IOWR_ALTERA_AVALON_PIO_DATA(DS18B20_BASE, 0);
usleep(10);
dat >>= 1; //数据位右移
IOWR_ALTERA_AVALON_PIO_DATA(DS18B20_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DIRECTION(DS18B20_BASE, 0);//方向为输入
if(IORD_ALTERA_AVALON_PIO_DATA(DS18B20_BASE)) //读取总线上的数据
{
dat |= 0x80;
}
usleep(45);
}
return dat;
}
DS18B20.h文件
/*
* ds18b20.h
*
* Created on: 2020年12月4日
* Author: dpt
*/
#ifndef DS18B20_H_
#define DS18B20_H_
#include <stdio.h>
#include <sys/unistd.h>
#include <io.h>
#include <string.h>
#include <stdio.h>
#include "stdlib.h"
#include "stdint.h"
#include "system.h"
#include "alt_types.h"
#include "altera_avalon_pio_regs.h"
#define OW_SKIP_ROM 0xcc
#define DS18B20_CONVERT 0x44
#define DS18B20_READ 0xbe
//函数声明
void Write_DS18B20(unsigned char dat);
alt_u8 Init_DS18B20(void);
unsigned char Read_DS18B20(void);
#endif /* DS18B20_H_ */
main.c
#include "lcd9341.h"
#include <stdio.h>
#include "ds18b20.h"
#include "alt_types.h"
#include "priv/alt_legacy_irq.h"
#include "altera_avalon_pio_regs.h"
unsigned int T_dat;
unsigned int S0 = 0;
unsigned int MAX_T_dat = 25;
char a1[10]={};
char a2[10]={};
char a3[10]={};
char a4[10]={};
char a5[10]={};
char a6[10]={};
char a7[10]={};
void Read_Temperature();
int main()
{
printf("I am 666!\n");
LCD9341_Init();
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0xff);//灯灭
IOWR_ALTERA_AVALON_PIO_DATA(BUZZER_BASE, 1);//蜂鸣器不叫
POINT_COLOR=RED;
LCD_ShowString(20,70," MAX Temp = .0C");
sprintf(a3,"%d",MAX_T_dat/10);
sprintf(a4,"%d",MAX_T_dat%10);
LCD_ShowString(132,70,a3);
LCD_ShowString(140,70,a4);
LCD_ShowString(20,50,"Temperature = ");
Read_Temperature();
printf("%d\n",T_dat);
sprintf(a1,"%d",T_dat/10);
sprintf(a2,"%d",T_dat%10);
LCD_ShowString(132,50,a1);
LCD_ShowString(148,50,".");
LCD_ShowString(156,50,a2);
LCD_ShowString(164,50,"C");
usleep(1000000);
while(1)
{
//按下S0,开始检测温度
if(IORD_ALTERA_AVALON_PIO_DATA(S0_BASE) == 0)
{
usleep(5000);
if(IORD_ALTERA_AVALON_PIO_DATA(S0_BASE) == 0)
{
if(S0 == 1) S0 = 0;
else S0 = 1;
while(IORD_ALTERA_AVALON_PIO_DATA(S0_BASE) == 0)//如果S0不松开
{
Read_Temperature();
printf("%d\n",T_dat);
sprintf(a1,"%d",T_dat/10);
sprintf(a2,"%d",T_dat%10);
LCD_ShowString(132,50,a1);
LCD_ShowString(148,50,".");
LCD_ShowString(156,50,a2);
LCD_ShowString(164,50,"C");
usleep(100000);
}
}
}
//按下S1阈值温度增加一个//注意这里每按下一次
if(IORD_ALTERA_AVALON_PIO_DATA(S1_BASE) == 0)
{
usleep(5000);
if(IORD_ALTERA_AVALON_PIO_DATA(S1_BASE) == 0 && S0 == 0)
{
MAX_T_dat++;
sprintf(a3,"%d",MAX_T_dat/10);
sprintf(a4,"%d",MAX_T_dat%10);
LCD_ShowString(132,70,a3);
LCD_ShowString(140,70,a4);
while(IORD_ALTERA_AVALON_PIO_DATA(S1_BASE) == 0);//判断按键是否松开
}
else if(IORD_ALTERA_AVALON_PIO_DATA(S1_BASE) == 0 && S0 == 1)
{
MAX_T_dat--;
if(MAX_T_dat > 0)
{
sprintf(a5,"%d",MAX_T_dat/10);
sprintf(a6,"%d",MAX_T_dat%10);
LCD_ShowString(132,70,a5);
LCD_ShowString(140,70,a6);
}
else
{
sprintf(a7,"%d",MAX_T_dat);
LCD_ShowString(132,70,a7);
}
while(IORD_ALTERA_AVALON_PIO_DATA(S1_BASE) == 0);//判断按键是否松开
}
}
//超过设置温度,灯亮,否则灯灭
if(T_dat/10> MAX_T_dat)
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(BUZZER_BASE, 0);//蜂鸣器叫
}
if(T_dat/10 < MAX_T_dat)
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0xff);
IOWR_ALTERA_AVALON_PIO_DATA(BUZZER_BASE, 1);//蜂鸣器不叫
}
}
}
//读温度
void Read_Temperature()
{
unsigned char LSB,MSB ;
Init_DS18B20();
Write_DS18B20(0xCC);
Write_DS18B20(0x44);
usleep(500000);//500ms
Init_DS18B20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
Init_DS18B20();
T_dat = 0x0000;
T_dat = MSB;
T_dat <<= 8;
T_dat = T_dat | LSB;
if((T_dat & 0xf800) == 0x0000)
{
T_dat >>= 4;
T_dat = T_dat*10;
T_dat = T_dat + (LSB&0x0f)*0.625;
}
}
第四部分、总结
1、接线图
2、实现功能阐述
按照题意,只有我按下我FPGA上的按键S0不放,开始检测温度,松开后停止检测。按下S1并松开,则温度的阈值就会增加一度,如果想减小阈值温度,那么先按一下S0,然后在按一下S1,这时候温度的阈值就会减少一度。同时当温度超过阈值时蜂鸣器报警。
3、结果演示
这里只展示图片,视频文件我已经上传到群文件,你也可以点击这里看一下演示效果(https://live.csdn.net/v/121253)。
4、完整工程
嫖嫖怪时间到,还是一样可以自己去群资料下载,也可以留下邮箱我偷偷发链接给你,或者老板大气一下,让我骗你几个积分(https://download.csdn.net/download/Learning1232/13695461)。