基于MM32F0140制作的温度计
WeDesign第1期 灵动微电子 MM32F0140 OLED IIC 温度 DS1825
标签
嵌入式系统
测试
数字逻辑
aramy
更新2023-05-29
425

硬件介绍:WeDesign活动是硬禾学堂发起的“一起设计、一起体验”活动。同学们可以通过提交申请来获取芯片、仪器、工具等。如果你能在规定时间内完成相应的任务,就可以获取补贴费用,优质作品更是有丰厚的奖励。
硬禾学堂推出的新活动,第一期是基于灵动微电子的MM32F0140。这颗芯片是使用高性能的 Arm Cortex-M0 为内核的 32 位微控制器,最高工作频率可达 72MHz,内置高速存储器,丰富的增强型 I/O 端口和多种外设。MM32F0140微控制器集成了FlexCAN外设,这是一个在汽车电子系统中常用的外设模块,配合适当的软件,可用于实现连入CAN总线网络的嵌入式系统产品。
看到这颗芯片的介绍,觉着和STM32f103系的芯片超级相似,自己有使用过STM32的芯片,但是最近几年,缺芯问题,已经让STM32系列的芯片变成了理财产品了。正好了解一下国产芯片,于是就写邮件参加了这次的活动。

任务选择:自己定了个小目标:了解一下这个MM32F0140芯片的性能,和用过的STM32F103的芯片做个比较,了解一下差异的地方。想用这个芯片制作一个温度计,使用OLED屏幕做显示。

硬件制作:购买了芯片后,想玩起来,第一步需要有一个开发板。跟着老师学习,了解到这个芯片烧写可以通过SWD方式写程序(这里和stm32f103一致),编写程序使用MDK。手头有颗美信的DS1825,还有几个电子烟上拆下的0.69寸的OLED。正好把这些硬件整合起来。
FlGpX1ElIHE28jc0w7_3K5Z6TZye

参考灵动微电子的mini-f0140开发板的电路图,绘制起了自己的电路图。这里结合自己手头的硬件做了些许改动。烧写口,手头有自制的DAPlink,是集成了SWD和串口的DAPLink,这里直接使用排母,就可以和DAPlink模块对插了。电源使用microusb作为电源输入,使用一颗ME6206A33P1G作为降压芯片给MM32F0140供电。OLED显示屏需要高压供电,所以这里增加了OLED的升压电路,提供了一路10v的电源。并且额外使用了2个IO口,用来重置OLED屏幕,和控制OLED的升压使能。IIC口做了上拉。添加了DS1825芯片电路。按键只保留了复位按键。CAN部分电路完全不懂,所以照着官方的电路图抄了过来。所有的IO口,都做了引出。
FpjDJTayAbRRK_UHKjkAOuYgOQk3这里需要说明一下,因为使用了免费的打样,所以PCB并没有直接在KiCad上绘制。而且KiCad中有少量元件封装没有,脑壳痛。这里使用了4层板(板子层数越多,PCB走线越简单^_^)。板子布局考虑了能在面包板上使用,所以两组IO引出的排针,上下布局,间隔为1000mil,不过打完板后发现,插到面包板上,正好和单块面包板宽度一样了,没法直接使用面包板了。这里晶振使用了一颗3脚的8M的晶振,体积更小,而且貌似集成了匹配电容,所以板子上就省去了匹配电容。DS1825放在了右下角,并且开槽和电路板做了物理隔离,防止温度的传导。四个角放置了4个2mm螺丝孔,可以安装铜柱。

FixC2uEWsDSxGwwirslJhfmA5IN1

FkgfUMXsr7AKSONLXjf46LLOihc-收到打样后的板子,使用我的电熨斗大法焊接。其实这次的MM32F0140是32脚,管脚还是比较稀疏的,手工焊接难度不大。不过习惯用电熨斗来焊接了,更快更容易。CAN部分还不会玩,只焊接了芯片,对应的排针暂时没有焊。烧写部分的接口,设计时,用的是90度的排母,最好发现还是用普通排母好看些,DAPLink就垂直着插即可。
Fq_QTJYUvw5PYYwdakkj8wPLSIo7Fq-HpFJTqMij97d2wbVD1VjwrI4Y
软件实现:运气不错,居然焊好板子后,第一次就烧写成功啦!从灵动微电子官网可以下载到MDK的样例程序,下载后打开工程,只需要设置一下烧写方式,选中CMSIS-DAP方式,就可以成功写入程序。这一块感觉比STM32F103做得好,烧写非常稳定。接下来开始实现自己的温度计设计。
FteGNaHPSEH50UjIh6LgqgFqx4VP下载例程,所有的开始都是从例程开始的。使用mini-f0140_i2c_master_detect_mdk的例程。不得不说灵动微电子代码架构很不错,框架清晰。首先看GPIO的操作,和STM32F103的函数非常相似,操作GPIO口的函数基本都可以按函数名称找到对应的方法。不过遇到第一个问题,例程中没看见延时函数。stm32中延时函数可以使用systick中断来实现,想必这里也一样。查阅资料,果然,先实现systick的延时。在clock_init.c中实现 微妙、毫秒的延时。

void BOARD_InitBootClocks(void)
{
    CLOCK_ResetToDefault();
    CLOCK_BootToHSE48MHz();

    /* UART2. */
    RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_UART2, true);
    RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_UART2);

    /* GPIOA. */
    RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOA, true);
    RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOA);

    /* GPIOB. */
    RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOB, true);
    RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOB);

    /* I2C1. */
    RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_I2C1, true);
    RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_I2C1);
	
		//systick 初始化
		fac_us=CLOCK_SYS_FREQ/8000000;                 
    fac_ms=(uint16_t)fac_us*1000;     
}void delay_us(uint32_t nus)
{        
    uint32_t temp;             
    SysTick->LOAD=nus*fac_us;                              
    SysTick->VAL=0x00;                            
    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;     
    do
    {
        temp=SysTick->CTRL;
    }while((temp&0x01)&&!(temp&(1<<16)));          
    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    
    SysTick->VAL =0X00;                           
}

void delay_ms(uint16_t nms)
{                     
    uint32_t temp;           
    SysTick->LOAD=(uint32_t)nms*fac_ms;                
    SysTick->VAL =0x00;                            
    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;    
    do
    {
        temp=SysTick->CTRL;
    }while((temp&0x01)&&!(temp&(1<<16)));          
    SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;    
    SysTick->VAL =0X00;                                    
}

有了延时,就来实现单总线协议。DS1825使用的是单总线协议,和DS18B20协议一样,只要控制好延时,就能很方便地通过一个GPIO管脚(PB0)写入、读取这枚温度传感器。DS18B20的单总线协议网上可以查到的资料很多,这里就不赘述了。

#include "DS18B20.H"
// 输出模式
void mode_output(void)
{
	GPIO_Init_Type gpio_init;
	gpio_init.Pins = TEMP_Pin;
	gpio_init.PinMode = GPIO_PinMode_Out_PushPull;
	gpio_init.Speed = GPIO_Speed_50MHz;
	GPIO_Init(TEMP_Port, &gpio_init);
}
// 输入模式
void mode_input(void)
{
	GPIO_Init_Type gpio_init;
	gpio_init.Pins = TEMP_Pin;
	gpio_init.PinMode = GPIO_PinMode_In_PullUp;
	GPIO_Init(TEMP_Port, &gpio_init);
}

// 复位DS18B20
void DS18B20_Rst(void)
{
	mode_output();
	GPIO_ClearBits(TEMP_Port, TEMP_Pin); // 拉低
	delay_us(750);						 // 拉低750us
	GPIO_SetBits(TEMP_Port, TEMP_Pin);	 // 输出1
	delay_us(15);						 // 15US
}

// 等待DS18B20的回应
// 返回1:未检测到DS18B20的存在
// 返回0:存在
uint8_t DS18B20_Check(void)
{
	uint8_t retry = 0;
	mode_input();
	while (GPIO_ReadInDataBit(TEMP_Port, TEMP_Pin) && retry < 200)
	{
		retry++;
		delay_us(1);
	};
	if (retry >= 200)
		return 1;
	else
		retry = 0;
	while (!GPIO_ReadInDataBit(TEMP_Port, TEMP_Pin) && retry < 240)
	{
		retry++;
		delay_us(1);
	};
	if (retry >= 240)
		return 1;
	return 0;
}

// 初始化DS18B20的IO口 DQ 同时检测DS的存在
// 返回1:不存在
// 返回0:存在
uint8_t DS18B20_Init(void)
{
	GPIO_Init_Type gpio_init; // B口时钟已经使能。

	gpio_init.Pins = TEMP_Pin; // PORTG.11 推挽输出
	gpio_init.PinMode = GPIO_PinMode_Out_PushPull;
	gpio_init.Speed = GPIO_Speed_50MHz;
	GPIO_Init(TEMP_Port, &gpio_init);

	GPIO_SetBits(TEMP_Port, TEMP_Pin); // 输出1
	DS18B20_Rst();
	return DS18B20_Check();
}

// 从DS18B20读取一个位
// 返回值:1/0
uint8_t DS18B20_Read_Bit(void)
{
	uint8_t data;
	mode_output();
	GPIO_ClearBits(TEMP_Port, TEMP_Pin); // 拉低
	delay_us(2);
	GPIO_SetBits(TEMP_Port, TEMP_Pin); // 拉高
	mode_input();
	delay_us(5);
	if (GPIO_ReadInDataBit(TEMP_Port, TEMP_Pin))
		data = 1;
	else
		data = 0;
	delay_us(5);
	return data;
}
// 从DS18B20读取一个字节
// 返回值:读到的数据
uint8_t DS18B20_Read_Byte(void)
{
	uint8_t i, j, dat = 0;
	for (i = 1; i <= 8; i++)
	{
		j = DS18B20_Read_Bit();
		dat = (j << 7) | (dat >> 1);
	}
	return dat;
}
// 写一个字节到DS18B20
// dat:要写入的字节
void DS18B20_Write_Byte(uint8_t dat)
{
	uint8_t j, testb;
	mode_output();
	for (j = 1; j <= 8; j++)
	{
		testb = dat & 0x01;
		dat = dat >> 1;
		if (testb)
		{
			GPIO_ClearBits(TEMP_Port, TEMP_Pin); // 拉低
			delay_us(2);
			GPIO_SetBits(TEMP_Port, TEMP_Pin); // 拉高
			delay_us(60);
		}
		else
		{
			GPIO_ClearBits(TEMP_Port, TEMP_Pin); // 拉低
			delay_us(60);
			GPIO_SetBits(TEMP_Port, TEMP_Pin); // 拉高
			delay_us(2);
		}
	}
}
// 开始温度转换
void DS18B20_Start(void)
{
	DS18B20_Rst();
	DS18B20_Check();
	DS18B20_Write_Byte(0xcc); // skip rom
	DS18B20_Write_Byte(0x44); // convert
}

// 从ds18b20得到温度值
// 精度:0.1C
// 返回值:温度值 (-550~1250)
float DS18B20_Get_Temp(void)
{
	uint8_t temp;
	uint8_t TL, TH;
	int8_t stat;
	// short tem;
	// float temp
	DS18B20_Start(); // ds1820 start convert
	DS18B20_Rst();
	DS18B20_Check();

	DS18B20_Write_Byte(0xcc); // skip rom
	DS18B20_Write_Byte(0xbe); // convert
	TL = DS18B20_Read_Byte(); // LSB
	TH = DS18B20_Read_Byte(); // MSB
	if ((TH & 0x80) == 0x80)
	{ // 判断温度正负
		TH = ~TH;
		TL = ~TL + 1; // 负温度处理(DS18B20的负温度是正的反码,即将它取反+1,就得到正的温度)
		stat = 1;
	}
	else
	{
		stat = 0;
	}
	if (stat)
		return (-1) * ((TH * 256 + TL) * 0.0625);
	return (TH * 256 + TL) * 0.0625;
}

显示屏幕使用了一片主控为SSD1307Z的0.69寸96x16的oled屏幕。使用IIC驱动。尝试使用mini-f0140_i2c_master_basic_mdk例程来驱动,能够访问IIC设备。这里有个很有意思的地方,MM32F0140的管脚是可以复用的。我这里IIC使用的是PA4、PA5。所以就需要用AF5指定管脚为I2C的管脚。

void BOARD_InitPins(void)
{
    /* PA2 - UART2_TX. */
    GPIO_Init_Type gpio_init;
    gpio_init.Pins  = GPIO_PIN_2;
    gpio_init.PinMode  = GPIO_PinMode_AF_PushPull; //GPIO_PinMode_AF_PushPull
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(GPIOA, gpio_init.Pins, GPIO_AF_1);

    /* PA3 - UART2_RX. */
    gpio_init.Pins  = GPIO_PIN_3;
    gpio_init.PinMode  = GPIO_PinMode_In_Floating; //GPIO_PinMode_In_Floating
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(GPIOA, gpio_init.Pins, GPIO_AF_1);

    /* I2C1_SCL. */
    gpio_init.Pins  = GPIO_PIN_5;
    gpio_init.PinMode  = GPIO_PinMode_AF_OpenDrain;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_PinAFConf(GPIOA, gpio_init.Pins, GPIO_AF_5);

    /* I2C1_SDA. */
    gpio_init.Pins  = GPIO_PIN_4;
    gpio_init.PinMode  = GPIO_PinMode_AF_OpenDrain;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_5);
}

FlsWmSEPzlC6NIEiWN7rjIHxBOE6

可惜折腾了很久,可以成功读到OLED的IIC地址,但是就没法显示内容,不太清楚什么原因。最后直接移植了stm32f103的模拟IIC的代码,成功驱动了OLED。

// GPIO初始化
void SI2C_GPIOInitConfig(void)
{
    GPIO_Init_Type gpio_init;
    /* I2C1_SCL. */
    gpio_init.Pins = I2C_SCL_PIN | I2C_SDA_PIN;
    gpio_init.PinMode = GPIO_PinMode_Out_PushPull;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(I2C_Port, gpio_init.Pins, GPIO_AF_1);
    GPIO_SetBits(I2C_Port, I2C_SCL_PIN | I2C_SDA_PIN); // 设置初始电平为高电平
}

// SDA设置为输出模式
static void SDA_OUT(void)
{
    GPIO_Init_Type gpio_init;
    gpio_init.Pins = I2C_SDA_PIN;
    gpio_init.PinMode = GPIO_PinMode_Out_PushPull;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(I2C_Port, &gpio_init);
    GPIO_SetBits(I2C_Port, I2C_SDA_PIN);
}

// SDA输入模式
static void SDA_IN(void)
{
    GPIO_Init_Type gpio_init;
    gpio_init.Pins = I2C_SDA_PIN;
    gpio_init.PinMode = GPIO_PinMode_In_PullUp;
    GPIO_Init(I2C_Port, &gpio_init);
}

void SI2C_Start()
{
    SDA_OUT();    // 设置SDA输出模式
    SI2C_SDA_1(); // 将SDA设置为高电平
    SI2C_SCL_1(); // 将SCL设置为高电平
    delay_us(8);
    SI2C_SDA_0(); // 将SDA设置为低电平
    delay_us(8);
    SI2C_SCL_0(); // 将SCL设置为低电平
}

void SI2C_Stop()
{
    SDA_OUT();    // 设置SDA输出模式
    SI2C_SDA_0(); // 将SDA设置为低电平
    SI2C_SCL_1(); // 将SCL设置为高电平
    delay_us(8);
    SI2C_SDA_1(); // 将SDA设置为高电平
    delay_us(8);
}

void SI2C_SendACK(uint8_t ack)
{
    SDA_OUT();
    SI2C_SCL_0();
    delay_us(8);
    if (ack)
        SI2C_SDA_1();
    else
        SI2C_SDA_0();
    SI2C_SCL_1();
    delay_us(8);
    SI2C_SCL_0();
    delay_us(8);
}

uint8_t SI2C_RecvACK(void)
{
    uint8_t ucErrTime = 0;

    SDA_IN();     // 设置SDA输入模式
                  //	I2C_SDA_1();
                  //	delay_us(4);
    SI2C_SCL_1(); // 将SCL设置为高电平
    delay_us(4);

    while (SI2C_SDA_READ()) // 检测SDA上是否出现低电平(ACK)
    {
        ucErrTime++;
        if (ucErrTime > 250) // 超时间差
        {
            SI2C_Stop(); // 停止通信
            return 1;
        }
    }
    SI2C_SCL_0(); // 将SCL设置为低电平
    return 0;
}

void SI2C_SendByte(uint8_t dat)
{
    uint8_t t;
    SDA_OUT();
    SI2C_SCL_0();
    for (t = 0; t < 8; t++)
    {
        //        SDA=(dat&0x80)>>7;
        if (dat & 0x80)
            SI2C_SDA_1(); // 将数据线上的电位设置好
        else
            SI2C_SDA_0();
        dat <<= 1;
        delay_us(5);
        SI2C_SCL_1(); // 时钟变化,数据发送出去
        delay_us(5);
        SI2C_SCL_0();
        delay_us(5);
    }
    SI2C_RecvACK();
}

uint8_t SI2C_RecvByte(void)
{
    int i = 0;
    uint8_t byte = 0;
    SDA_IN();
    for (i = 0; i < 8; i++)
    {
        delay_us(5);
        SI2C_SCL_1(); // 先接受一次数据线上的数据到寄存器
        delay_us(5);
        byte <<= 1;
        if (SI2C_SDA_READ()) // 判断寄存器中的数据
        {
            byte |= 0x01;
        }
        SI2C_SCL_0();
        delay_us(5);
    }
    return byte;
}

/****************************************************************************
 *	函 数 名: i2c_CheckDevice
 *	功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
 *	形    参:_Address:设备的I2C总线地址
 *	返 回 值: 返回值 0 表示正确, 返回1表示未探测到
 ****************************************************************************/
uint8_t I2C_CheckDevice(uint8_t _Address)
{
    uint8_t ucAck;

    SI2C_Start(); /* 发送启动信号 */

    /* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
    SI2C_SendByte(_Address | I2C_WR);
    ucAck = SI2C_RecvACK(); /* 检测设备的ACK应答 */

    SI2C_Stop(); /* 发送停止信号 */

    return ucAck;
}

//========OLED控制部分=====================================================
void OledWriteCmd(uint8_t cmd)
{
    SI2C_Start();
    SI2C_SendByte(0x78);
    SI2C_SendByte(0x00);
    SI2C_SendByte(cmd);
    SI2C_Stop();
}
void OledWriteData(uint8_t dt)
{
    SI2C_Start();
    SI2C_SendByte(0x78);
    SI2C_SendByte(0x40);
    SI2C_SendByte(dt);
    SI2C_Stop();
}

void OledFillData(uint8_t Data)
{
    uint8_t i, j;
    for (i = 0xB0; i < 0xB3; i++)
    {
        OledWriteCmd(i);
        OledWriteCmd(0x00);
        OledWriteCmd(0x12);
        for (j = 0; j < 128; j++)
        {
            OledWriteData(Data);
        }
    }
}
void oled_init(void)
{
    SI2C_GPIOInitConfig();

    OledWriteCmd(0xAE); // display off
    OledWriteCmd(0xd5); // Set Display ClocDivide Ratio/Oscillator Frequency
    OledWriteCmd(0xc4); // 100HZ

    OledWriteCmd(0xa8); //--set multiplex ratio(1 to 64)
    OledWriteCmd(0x0f); // set 16mux
    OledWriteCmd(0xd9); // Set Pre-charge Period
    OledWriteCmd(0x22);

    OledWriteCmd(0x20); // Set Memory Addressing Mode
    OledWriteCmd(0x02);

    if (DISPDIC == 0)
    {
        OledWriteCmd(0xa0); // seg re-map 0->127
        OledWriteCmd(0xc8); // COM scan direction COM(N-1)-->COM0
    }
    else
    {
        OledWriteCmd(0xa1); // seg re-map 0->127
        OledWriteCmd(0xc0); // COM scan direction COM(N-1)-->COM0
    }

    OledWriteCmd(0xda); // Set COM Pins Hardware Configuration
    OledWriteCmd(0x12); //
    OledWriteCmd(0x81); // Set Contrast Control
    OledWriteCmd(0x0c); //
    OledWriteCmd(0xb0); // Set Page Start Address for Page Addressing Mode

    OledWriteCmd(0xd3); // Set Display offset
    OledWriteCmd(0x1f); //
    OledWriteCmd(0xa6); // Display Normal(ÕýÏÔ)
    OledWriteCmd(0xa4); // Entire Display Off
    OledWriteCmd(0xdb); // Set VCOMH Level()
    OledWriteCmd(0x30); // 0.83*VCC

    OledWriteCmd(0xaf); // 打开显示
    OledFillData(0x00); // 初始清屏
}

//=========================================================//OLED关闭
void OledOff(void)
{
    OledWriteCmd(0xAE); // 关闭显示
}

//=========================================================//OLED打开
void OledOn(void)
{
    OledWriteCmd(0xAF); // 打开显示
}

//=========================================================//设置Y地址
void OledSetAddY(uint8_t AddY)
{
    OledWriteCmd(0xB0 + AddY); // OLED地址Y
}

//=========================================================//设置X地址
void OledSetAddX(uint8_t AddX)
{
    AddX *= 6;               // 每个字符总列数
    OledWriteCmd(AddX % 16); // 低字节(0-15)
    if (DISPDIC == 0)
    {
        OledWriteCmd(0x12 + (AddX / 16)); // 高字节()0x10为偏移量
    }
    else
    {
        OledWriteCmd(0x10 + (AddX / 16));
    }
}

//=========================================================//在指定位置写数据
// 每个字占2位,16位总共可以写8个数字
void OledWriteWord(uint8_t AddX, uint8_t ch)
{
    uint8_t x;
    OledSetAddX(AddX);
    OledSetAddY(0);
    for (x = 0; x < 8; x++)
    {
        OledWriteData(MCharTab[ch][x]);
    }
    OledSetAddX(AddX);
    OledSetAddY(1);
    for (x = 0; x < 8; x++)
    {
        OledWriteData(MCharTab[ch][x + 8]);
    }
}
//=========================================================//在指定位置写数据
void OledWriteChar(uint8_t AddX, uint8_t AddY, uint8_t ch)
{
    unsigned char x;
    OledSetAddX(AddX);
    OledSetAddY(AddY);
    for (x = 0; x < 7; x++)
    {
        OledWriteData(CharTab[ch][x]);
    }
}
// 根据温度显示 cold cool warm hot
void OledDispStr(int temperature)
{
    if (temperature >= 13 && temperature < 20)
    { // cool
        OledWriteChar(12, 1, 12);
        OledWriteChar(13, 1, 24);
        OledWriteChar(14, 1, 24);
        OledWriteChar(15, 1, 21);
    }
    if (temperature < 13)
    { // cold
        OledWriteChar(12, 1, 12);
        OledWriteChar(13, 1, 24);
        OledWriteChar(14, 1, 21);
        OledWriteChar(15, 1, 13);
    }
    if (temperature >= 20 && temperature < 29)
    { // warm
        OledWriteChar(12, 0, 32);
        OledWriteChar(13, 0, 10);
        OledWriteChar(14, 0, 27);
        OledWriteChar(15, 0, 22);
    }
    if (temperature >= 29)
    { // hot
        OledWriteChar(12, 0, 17);
        OledWriteChar(13, 0, 24);
        OledWriteChar(14, 0, 29);
        OledWriteChar(15, 0, 36);
    }
}
// 显示浮点数,整数位显示3位,小数位显示1位 共5个数字
void OledDispTemperature(float num)
{
    uint8_t i;
    OledWriteWord(0, 10);
    if (num < 0)
    {
        num = -num;
        OledWriteWord(0, 14);
    }
    else
    {
        i = num / 100;
        if (i > 0)
        {
            OledWriteWord(0, i);
        }
        num = num - i * 100;
    }

    i = num / 10;
    if (i > 0)
    {
        OledWriteWord(2, i);
    }
    num = num - i * 10;

    i = num;
    if (i >= 0)
    {
        OledWriteWord(4, i); // 个位
    }
    num = num - i;

    OledWriteWord(6, 11); // 显示小数点

    i = (num * 100 + 5) / 10;
    if (i >= 0)
    {
        OledWriteWord(8, i);
    }
    OledWriteChar(10, 1, 41);
}

Fkt7A5LzyJjJnPX5ZjBAJwOcem3NFrOWmQ1GfNeXr_XuUsygXcE1JF5x

心得体会:感谢硬禾学堂提供的这次活动。通过接触了MM32F0140的这几周时间,真心觉得做得比STM32F103好。烧写、调试都很稳定。更多的想了解CAN总线的使用,但是自己没有接触过,借助这次机会获得硬件,向老师和同学们学习一番。

附件下载
mini-f0140_i2c_oled.zip
fthr-f0140.kicad_sch
PCB_PCB_mini-f0140开发板_2023-04-27.kicad_pcb
团队介绍
折腾小能手。
团队成员
aramy
单片机业余爱好者,瞎捣鼓小能手。
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号