感谢iceasy与火萤工厂提供的GD32VW553-IOT开发板
结合现有的51开发板的中硬件做一个温度计,如下图所示:
main.c文件内容
#include "gd32vw55x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "DS18B20.h"
#include "74HC595.h"
extern uint8_t seg_position[8];
extern uint8_t seg_code[17];
//从DS18B20读取的是float格式温度,而74HC595下发的是uint8_t格式数据
//因此需要将float数据转换为uint8_t数据
//定义一个数组用来重构数码管的显示字符
uint8_t seg_temp_code[8];
void datapross(float dat)
{
//定义一个整形数据作为缓存变量
int a;
//判断温度的正负
if(dat<0)
{
seg_temp_code[0]=0x40;
dat=-dat;
}else{
seg_temp_code[0]=0x00;
}
//保留两位小数,并+0.5对原始数据的第三位小数进行四舍五入
a=dat*100+0.5;
seg_temp_code[1] = seg_code[a / 10000];
seg_temp_code[2] = seg_code[a % 10000 / 1000];
seg_temp_code[3] = seg_code[a % 1000 / 100] | 0X80;
seg_temp_code[4] = seg_code[a % 100 / 10];
seg_temp_code[5] = seg_code[a % 10];
seg_temp_code[6] = 0x00;
seg_temp_code[7] = 0x00;
}
/*
* 主函数
*/
int main(void)
{
//配置延迟时钟
systick_config();
uint8_t i;
//初始化
DS18B20_Init();
HC595_Init();
//消影
HC595_Write_data(0x00,0x00);
//检测DS18B20,(ds18b20调试成功)
while(DS18B20_Init())
{
//-轮流滚动说明器件通讯错误。
HC595_ALL(0x40);
}
while(1)
{
i=0;
datapross(DS18B20_GetTemperture());
for(i=0;i<8;i++)
{
HC595_Write_data(seg_temp_code[i],seg_position[i]);
}
//测试不消影也可用
//delay_1us(500);
//消影
//HC595_Write_data(0x00,0x00);
}
}
systick.c文件
#include "gd32vw55x.h"
#include "systick.h"
volatile static uint32_t delay;
void systick_config(void)
{
SysTimer_SetControlValue(SysTimer_MTIMECTL_CMPCLREN_Msk);
SysTimer_SetCompareValue(SystemCoreClock / 4000000);
__ECLIC_SetTrigIRQ(CLIC_INT_TMR, ECLIC_POSTIVE_EDGE_TRIGGER);
eclic_irq_enable(CLIC_INT_TMR, 0, 0);
}
void delay_1ms(uint32_t count)
{
delay = count * 1000;
while(0U != delay) {
}
}
//定义微秒函数
void delay_1us(uint32_t count)
{
delay = count;
while(0U != delay) {
}
}
void delay_decrement(void)
{
if(0U != delay) {
delay--;
}
}
systick.h文件
#ifndef SYSTICK_H
#define SYSTICK_H
#include <stdint.h>
void systick_config(void);
void delay_1ms(uint32_t count);
//us延迟函数
void delay_1us(uint32_t count);
void delay_decrement(void);
#endif
74HC595.c文件:
#include "gd32vw55x.h"
#include "74HC595.h"
#include "systick.h"
//两个74HC595级联,靠近单片的74HC595用于数码管段选,次级74HC595用于未选,
//即十六位数据中低8位用于显示数字,高8位用于选择数码管位置
//动态数码管采用共阴极结构方式,
//定义数码管显示数组
uint8_t seg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//定义数码管显示位,共阴极,取反码
uint8_t seg_position[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
//初始化数据引脚为输出模式
uint8_t HC595_Init()
{
//开启时钟
rcu_periph_clock_enable(HC595_PORT_RCC);
//设置端口模式
gpio_mode_set(HC595_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,HC595_PIN_SRCLK | HC595_PIN_RCLK |HC595_PIN_SER); //浮空输出
gpio_output_options_set(HC595_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX,HC595_PIN_SRCLK | HC595_PIN_RCLK |HC595_PIN_SER); //设置输出模式
//初始化为低电平输出,提高稳定性
HC595_PIN_SER_Low();
HC595_PIN_SRCLK_Low();
HC595_PIN_RCLK_Low();
}
//写数据,HCHdata存储数码管位置信息,HCLdata显示数字信息
void HC595_Write_data(uint8_t HCLdata,uint8_t HCHdata)
{
//合并数据
uint16_t HCdata;
HCdata=((HCHdata<<8)|HCLdata);
//写高16位
uint8_t a=0;
for(a=0;a<16;a++)//循环8次即可将一个字节写入寄存器中
{
//优先传输数据中的高位
if(HCdata & 0x8000)
{
HC595_PIN_SER_High();
}else
{
HC595_PIN_SER_Low();
}
HCdata<<=1;//将低位移动到高位
HC595_PIN_SRCLK_Low();
delay_1us(10);
HC595_PIN_SRCLK_High();
delay_1us(10);//移位寄存器时钟上升沿将端口数据送入寄存器中
}
HC595_PIN_RCLK_Low();
delay_1us(10);
HC595_PIN_RCLK_High();//存储寄存器时钟上升沿将前面写入到寄存器的数据输出
delay_1us(500);
//数据针脚低电平输出,提高稳定性
HC595_PIN_SER_Low();
HC595_PIN_SRCLK_Low();
HC595_PIN_RCLK_Low();
}
//轮动显示某个数据
void HC595_ALL(uint8_t dat)
{
uint8_t Ldat;
uint8_t i;
Ldat=0x01;
for(i=0;i<8;i++)
{
HC595_Write_data(dat,~Ldat);
Ldat<<=1;
delay_1ms(200);
if(Ldat==0x00)
{
Ldat=0x01;
}
}
}
74HC595.h文件:
#ifndef __74HC595_h
#define __74HC595_h
extern uint8_t seg_code[17];
//定74HC595通讯引脚与时钟
#define HC595_PORT GPIOA
#define HC595_PIN_SRCLK GPIO_PIN_1
#define HC595_PIN_RCLK GPIO_PIN_2
#define HC595_PIN_SER GPIO_PIN_3
#define HC595_PORT_RCC RCU_GPIOA
#define HC595_PIN_SRCLK_High() gpio_bit_set(HC595_PORT,HC595_PIN_SRCLK)
#define HC595_PIN_SRCLK_Low() gpio_bit_reset(HC595_PORT,HC595_PIN_SRCLK)
#define HC595_PIN_RCLK_High() gpio_bit_set(HC595_PORT,HC595_PIN_RCLK)
#define HC595_PIN_RCLK_Low() gpio_bit_reset(HC595_PORT,HC595_PIN_RCLK)
#define HC595_PIN_SER_High() gpio_bit_set(HC595_PORT,HC595_PIN_SER)
#define HC595_PIN_SER_Low() gpio_bit_reset(HC595_PORT,HC595_PIN_SER)
uint8_t HC595_Init(void);
void HC595_Write_data(uint8_t HCLdata,uint8_t HCHdata);
void HC595_ALL(uint8_t dat);
#endif
DS18B20.c文件:
#include "gd32vw55x.h"
#include "systick.h"
#include "DS18B20.h"
//设置DS18B20输入输出模式
void DS18B20_IO_OUT()
{
//设置端口模式
gpio_mode_set(DS18B20_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,DS18B20_PIN); //浮空输出
gpio_output_options_set(DS18B20_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_MAX,DS18B20_PIN); //设置输出模式
}
void DS18B20_IO_IN()
{
//设置端口输入模式
gpio_mode_set(DS18B20_PORT, GPIO_MODE_INPUT,GPIO_PUPD_NONE,DS18B20_PIN); //浮空输入
}
//复位DS18B20
void DS18B20_Rest()
{
DS18B20_IO_OUT();
gpio_bit_reset(DS18B20_PORT,DS18B20_PIN);
delay_1us(750);
gpio_bit_set(DS18B20_PORT,DS18B20_PIN);
delay_1us(15);
}
//检测DS18B20是否存在
uint8_t DS18B20_Check(void)
{
uint8_t retry=0;
DS18B20_IO_IN();
while(gpio_input_bit_get(DS18B20_PORT,DS18B20_PIN) && retry<200) //引脚变为低电平则为响应存在
{
retry++;
delay_1us(1);
}
if(retry>=200)return 1;
else retry=0;
while(!gpio_input_bit_get(DS18B20_PORT,DS18B20_PIN) && retry<240)
{
retry++;
delay_1us(1);
}
if(retry>=240)return 1;
return 0;
}
//初始化DS18B20,检测DS18B20是否存在,0存在,1不存在
uint8_t DS18B20_Init(void)
{
//开启时钟
rcu_periph_clock_enable(DS18B20_PORT_RCC);
DS18B20_IO_OUT();
delay_1us(10);
DS18B20_Rest();
return DS18B20_Check();
}
//写字节,先写低位再写高位
void DS18B20_Write_Byte(uint8_t dat)
{
uint8_t i;
uint8_t Write_Byte=0;
DS18B20_IO_OUT();
for(i=0;i<8;i++)
{
Write_Byte = dat & 0x01; //取低位数据
dat>>=1;
if(Write_Byte)
{
//写1,先拉低2微秒,再拉高60微秒
gpio_bit_reset(DS18B20_PORT,DS18B20_PIN); //输出低电平
delay_1us(2);
gpio_bit_set(DS18B20_PORT,DS18B20_PIN); //输出高电平
delay_1us(60);
}else{
//写0,先拉低60微秒,再拉高2微秒
gpio_bit_reset(DS18B20_PORT,DS18B20_PIN); //输出低电平
delay_1us(60);
gpio_bit_set(DS18B20_PORT,DS18B20_PIN); //输出高电平
delay_1us(2);
}
}
}
//读一位数据
uint8_t DS18B20_Read_Bit(void)
{
uint8_t data=0;
DS18B20_IO_OUT();
gpio_bit_reset(DS18B20_PORT,DS18B20_PIN); //输出低电平,总线拉低两个微秒
delay_1us(2);
gpio_bit_set(DS18B20_PORT,DS18B20_PIN);
DS18B20_IO_IN();
delay_1us(12); //15us内读取数据
if(gpio_input_bit_get(DS18B20_PORT,DS18B20_PIN))data=1; //输入高电平则将data置1
else data=0;
delay_1us(50);
return data;
}
//读一个字节,先读低位后读高位
uint8_t DS18B20_Read_Byte(void)
{
uint8_t i=0;
uint8_t data;
uint8_t Read_Byte;
for(i=0;i<8;i++)
{
data=DS18B20_Read_Bit();
Read_Byte=(data<<7)|(Read_Byte>>1);
}
return Read_Byte;
}
//读取温度
float DS18B20_GetTemperture(void)
{
uint8_t a,b; //a用来保存低字节,b用来保存高字节
uint16_t temp;
float value;
DS18B20_Init();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0x44);
DS18B20_Init();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0xbe);
a=DS18B20_Read_Byte(); //读取低位
b=DS18B20_Read_Byte(); //读取高位
temp=(b<<8|a);
//判断高5位,正温度还是负温度?
if((temp & 0xf800)== 0xf800)
{
temp=(~temp)+1; //负温度为数据取反加1
value=temp*(-0.0625);
}else
{
value=temp*0.0625;
}
return value;
}
DS18B20.h文件:
#ifndef __DS18B20_h
#define __DS18B20_h
#include "gd32vw55x.h"
//定义DS18B20通讯引脚与时钟
#define DS18B20_PORT GPIOA
#define DS18B20_PIN GPIO_PIN_0
#define DS18B20_PORT_RCC RCU_GPIOA
//初始化,初始化成功则返回0,失败返回1
uint8_t DS18B20_Init();
//写字节,先写低位再写高位
void DS18B20_Write_Byte(uint8_t dat);
//读一个字节
uint8_t DS18B20_Read_Byte(void);
//读取温度
float DS18B20_GetTemperture(void);
#endif
