本代码为当时,参加嵌入式系统开发与应用赛项,训练时编写的自检程序,用于将程序烧录后,逐个演示板载模块功能是否正常,快速定位问题。这代码编写的时间为2023
年,好像原代码是参考2023年官方案例来编写的。目前代码版本,和模块应该已经更新,所以参考价值不一定高。还有当时在编写时,是有些坑的,例如LCD方向定义有点问题,好像哪个库代码还少了部分之类的,总之有时候,有些功能给了接口,但是功能没有实装的,不过现在源代码迭代了些,应该修复了不少吧。
- 软件:Embedded IDE for Loongson
- 开发板,如下图
下述为main.c代码,完整项目放在末尾。
#include <stdio.h>
#include "ls1b.h"
#include "mips.h"
//-------------------------------------------------------------------------------------------------
// BSP
//-------------------------------------------------------------------------------------------------
#include "bsp.h"
#include "led_drv.h"
#include "key_drv.h"
#include "beep.h"
#include "uart.h"
#include "lkdGui.h" // 显示库
#include "stdint.h" // 显示相关
#include "ls1x_i2c_bus.h" // i2C总线
#include "i2c/ads1015.h" // ADC芯片
#include "i2c/mcp4725.h" // ADC相关
#include "pwm_ic.h" // PWM相关
#include "bh1750_iic.h" // BH1750
#include "bh1750.h" // BH1750
#include "libc/lwmem.h" // LCD相关
#include "pic_flag.h" // 图片存放
#include "i2c/gt1151.h" // 触摸相关
#include "fan_resistance_control_drv.h" // 风扇控制
#include "lm35_drv.h" // 温度测量
#include "ls1b_gpio.h" // GPIO控制
#ifdef BSP_USE_FB
#include "ls1x_fb.h"
#ifdef XPT2046_DRV
char LCD_display_mode[] = LCD_800x480;
#elif defined(GT1151_DRV)
char LCD_display_mode[] = LCD_800x480;
#else
#error "在bsp.h中选择配置 XPT2046_DRV 或者 GT1151_DRV"
"XPT2046_DRV: 用于800*480 横屏的触摸屏."
"GT1151_DRV: 用于480*800 竖屏的触摸屏."
"如果都不选择, 注释掉本 error 信息, 然后自定义: LCD_display_mode[]"
#endif
#endif
/**** 辅助程序 ****/
unsigned int TaskTextRoll_Row = 0; // 行索引
unsigned char TaskTextRoll_RowHigh = 35; // 行高度
unsigned char JsMode_Num = 3; // 计数模式的倒计时
char textBuf[50]= {0};
// 任务文本滚动
// str:字符串
// mode:模式选择 0.默认显示模式 1.计数等待模式 2.顺序例出文本且间隔比较大
void TaskTextRoll(uint8_t *str ,uint8_t mode)
{
uint8_t i;
switch(mode)
{
case 0:
TaskTextRoll_Row += 1; // 行数递增
GuiRowText(30, 10+(TaskTextRoll_RowHigh * TaskTextRoll_Row) ,480, FONT_LEFT,str);
printk(str);
printk("\r\n");
break;
case 1:
delay_ms(1000);
for(i = 0; i < JsMode_Num; i++)
{
sprintf((char *)textBuf,"%d",JsMode_Num-i);
GuiRowText(280+(i*50), 10+(TaskTextRoll_RowHigh * TaskTextRoll_Row) ,30, FONT_LEFT,textBuf);
printk(textBuf);
printk(" ");
delay_ms(1000);
}
printk("\r\n");
break;
case 2:
TaskTextRoll_Row += 1; // 行数递增
GuiRowText(60, 30+(TaskTextRoll_RowHigh * TaskTextRoll_Row) ,480, FONT_LEFT,str);
printk(str);
printk("\r\n");
break;
default:
GuiRowText(30, (TaskTextRoll_RowHigh * TaskTextRoll_Row) ,480, FONT_LEFT,"显示错误!");
break;
}
}
unsigned char KEY_keyNum = 0;
unsigned char KEY_ExitKey = 4;
// 按键跳过程序
// 将该函数放置要循环的任务语句中
unsigned char KEY_SKipTask(void)
{
KEY_keyNum = KEY_Scan();
if(KEY_keyNum == KEY_ExitKey) return 0;
return 1;
}
//-------------------------------------------------------------------------------------------------
// 主程序
//-------------------------------------------------------------------------------------------------
/***** 任务函数 *****/
//任务1现象--红绿蓝分别保持1秒
void Task1_LED(void)
{
//printk("Task1_LED_start\r\n");
LED_Init();
while(KEY_SKipTask())
{
LED_RGBDemo();
}
//printk("Task1_LED_end\r\n");
}
//任务2现象-- S1-亮红灯 S2--亮绿灯 S3--亮蓝灯 S4--退出该任务
void Task2_KEY(void)
{
unsigned char keyNum = 0;
unsigned char status = 0;
KEY_Init();
//printk("Task2_KEY_start\r\n");
while(1)
{
keyNum = KEY_Scan();
status = 0;
switch ( keyNum )
{
case 1:
LED_On( LED1 );
LED_Off( LED2 );
LED_Off( LED3 );
delay_ms(500);
break;
case 2:
LED_On( LED2 );
LED_Off( LED1 );
LED_Off( LED3 );
delay_ms(500);
break;
case 3:
LED_On( LED3 );
LED_Off( LED1 );
LED_Off( LED2 );
delay_ms(500);
break;
case 4:
status = 1;
break;
default:
LED_Off( LED1 );
LED_Off( LED2 );
LED_Off( LED3 );
break;
}
if(status == 1) break;
}
//printk("Task2_KEY_end\r\n");
}
//任务3现象--蜂鸣器响起
void Task3_BEEP(void)
{
//printk("Task3_BEEP_start\r\n");
BEEP_Init();
BEEP_On();
delay_ms(500);
BEEP_Off();
delay_ms(500);
BEEP_On();
delay_ms(500);
BEEP_Off();
delay_ms(500);
BEEP_On();
delay_ms(500);
BEEP_Off();
delay_ms(500);
//printk("Task3_BEEP_end\r\n");
}
//任务4现象--UART交互(波特率115200)
void Task4_UART(void)
{
//printk("Task4_UART_start\r\n");
UART5_Config_Init();
LED_Off(LED1);
//串口控制函数
while(UART5_Test())
{
if(!(KEY_SKipTask())) break;
}
//printk("Task4_UART_end\r\n");
}
extern float temp;
double lm35_temp_data;
char str[100];
//任务5现象--风扇与加热
void Task5_FAN_HOT(void)
{
unsigned char i = 0;
unsigned int i_5S = 0;
unsigned char Tempfirst = 0; // 记录初始温度
unsigned char TempEnd = 0; // 记录最后温度
fan_resistance_io_Config();
gpio_write(38,1);//加热电阻打开
gpio_write(36,1);//风扇开关打开
Fan_Control(100);//风扇控制PWM最大
ls1x_i2c_initialize(busI2C0);
ls1x_ads1015_ioctl(busI2C0,IOCTL_ADS1015_DISP_CONFIG_REG,NULL);
GuiRowText(50, 550,400, FONT_MID, "加热30S电阻测温度");
//GuiRowText(50, 590,480, FONT_LEFT, "加热模式");
//GuiRowText(50, 590,480, FONT_LEFT, " ");
// 进入时测量(5S)
GuiRowText(50, 590,480, FONT_LEFT, "测量模式: 进行中");
GuiRowText(50, 630,400, FONT_LEFT, "当前温度:");
while(i_5S < 25)
{
lm35_get_temp();
GuiRowText(220, 630,480, FONT_LEFT, " ");
sprintf(str,"%.01f℃",temp);
GuiRowText(220, 630,400, FONT_LEFT, str);
delay_ms(200);
i_5S++;
}
Tempfirst = temp;
// 加热30S
GuiRowText(50, 590,480, FONT_LEFT, "加热模式: ");
for(i=0;i<30;i++)
{
GuiRowText(220, 590,480, FONT_LEFT, " ");
sprintf(str,"%d S",30-i);
GuiRowText(220, 590,480, FONT_LEFT, str);
delay_ms(1000);
}
gpio_write(38,0);//加热电阻关闭
gpio_write(36,0);//风扇开关关闭
GuiRowText(50, 590,480, FONT_LEFT, " ");
GuiRowText(50, 590,480, FONT_LEFT, "测量模式: 进行中");
GuiRowText(50, 630,400, FONT_LEFT, "当前温度:");
while(KEY_SKipTask())
{
lm35_get_temp();
GuiRowText(220, 630,480, FONT_LEFT, " ");
sprintf(str,"%.01f℃",temp);
GuiRowText(220, 630,400, FONT_LEFT, str);
delay_ms(200);
TempEnd = temp;
GuiRowText(220, 670,480, FONT_LEFT, " ");
sprintf(str,"初始温度:%d",Tempfirst);
GuiRowText(50, 670,400, FONT_LEFT, str);
GuiRowText(220, 710,480, FONT_LEFT, " ");
sprintf(str,"温度差值:%d",(TempEnd-Tempfirst)>0?TempEnd-Tempfirst:(TempEnd-Tempfirst)*(-1));
GuiRowText(50, 710,400, FONT_LEFT, str);
}
// 清除
fb_fillrect(0, 0, 350, 480, cidxBLACK);
}
//任务6现象--语音模块交互
void Task6_VOICE(void)
{
//printk("Task6_VOICE_start\r\n");
//printk("Task6_VOICE_end\r\n");
}
//任务数码管验证
void Task7_SMG(void)
{
//printk("Task7_SMG_start\r\n");
int num;
SMG_Init();
while(KEY_SKipTask())
{
num = 9999;
while(1)
{
SMG_SeleNumDyn(num,1000);
num -= 1111;
if(num == 0) break;
}
}
//printk("Task7_SMG_end\r\n");
}
char tbuf1[50]= {0},tbuf2[50]= {0},tbuf3[50]= {0},tbuf4[50]= {0},sbuf1[50]= {0},sbuf2[50]= {0},sbuf3[50]= {0},sbuf4[50]= {0},rt;
unsigned short dac=0, adc1=0, adc2=0, adc3=0, adc4=0;
float out_v,in_v1,in_v2,in_v3,in_v4;
void Task8_I2C_ADC(void)
{
unsigned char quitNum = 0;
unsigned int RowAdjust = 550; // Y 轴显示高度补偿
ls1x_ads1015_ioctl(busI2C0,IOCTL_ADS1015_DISP_CONFIG_REG,NULL);
while(KEY_SKipTask())
{
adc1 = get_ads1015_adc(busI2C0, ADS1015_REG_CONFIG_MUX_SINGLE_0);
adc2 = get_ads1015_adc(busI2C0, ADS1015_REG_CONFIG_MUX_SINGLE_1);
adc3 = get_ads1015_adc(busI2C0, ADS1015_REG_CONFIG_MUX_SINGLE_2);
adc4 = get_ads1015_adc(busI2C0, ADS1015_REG_CONFIG_MUX_SINGLE_3);
in_v1 = 4.096*2*adc1/4096;//采集电压的转换公式
in_v2 = 4.096*2*adc2/4096;//采集电压的转换公式
in_v3 = 4.096*2*adc3/4096;//采集电压的转换公式
in_v4 = 4.096*2*adc4/4096;//采集电压的转换公式
sprintf((char *)sbuf1,"CH 1 = %f V",in_v1);
sprintf((char *)sbuf2,"CH 2 = %f V",in_v2);
sprintf((char *)sbuf3,"CH 3 = %f V",in_v3);
sprintf((char *)sbuf4,"CH 4 = %f V",in_v4);
GuiRowText(30, 30+RowAdjust,400, FONT_LEFT, "ADS1015 ADC GET");
GuiRowText(30, 60+RowAdjust,400, FONT_LEFT,sbuf1);
GuiRowText(30, 90+RowAdjust,400, FONT_LEFT,sbuf2);
GuiRowText(30, 120+RowAdjust,400, FONT_LEFT,sbuf3);
GuiRowText(30, 150+RowAdjust,400, FONT_LEFT,sbuf4);
//fb_textout(10, 60, "ADS1015 ADC GET");
delay_ms(500);
quitNum ++;
//if(quitNum>10) break;
}
fb_fillrect(0, 0, 350, 480, cidxBLACK);
}
char data[20];
unsigned int frequency = 5000;
unsigned int x_i=0; //X轴绘图前进
void Task9_PWM(void)
{
unsigned int i = 0;
unsigned char isDown = 0;
GuiRowText(50, 550,400, FONT_LEFT, "PWM输出");
GuiRowText(50, 580,400, FONT_LEFT, "PWM输出占空比为:");
// 容器化(统一宽高)
// xy轴画线
GuiRLine(50,650,750,cidxRED);
GuiHLine(50,750,400,cidxRED);
//Set_PWM(500); // 20KMz
// 触顶低反弹
for(i = 0; isDown?i>=0:i<101 ; isDown?i--:i++)
{
sprintf(data,"%d ",i);
GuiRowText(320, 580,400, FONT_LEFT, data);
x_i++; // 递进数
GuiPoint(50+x_i,750-i,cidxGREEN); //绘制波形
// 设置PWM函数(我也不知道为啥这么设,只是验证后现象没问题)
// 数值越大越慢
Set_PWM(i*50);
delay_ms(100);
// 触顶低反弹逻辑
if(i == 0)
{
i=1 ;
isDown = 0;
}
else if(i == 100)
{
i=99 ;
isDown = 1;
}
// 退出逻辑
if(50 + x_i > 400)
{
break;
}
}
while(KEY_SKipTask());
fb_fillrect(0, 0, 350, 480, cidxBLACK);
}
unsigned int task10_ContY = 550;
void Task10_BH1750(void)
{
unsigned char buf[20] = {0};
unsigned int lx = 0;
BH1750_Init(); //光照强度传感器初始化
GuiRowText(50, 30+task10_ContY, 400, FONT_LEFT, "BH1750光照度传感器测量");
GuiRowText(50, 70+task10_ContY, 400, FONT_LEFT, "光照传感器");
GuiRowText(50, 110+task10_ContY, 400, FONT_LEFT, "当前光照强度:");
while(KEY_SKipTask())
{
// 循环检测部分
sprintf((char *)buf,"%d lux", BH1750_reData());
GuiRowText(280, 110+task10_ContY, 400, FONT_LEFT, buf);
}
fb_fillrect(0, 0, 350, 480, cidxBLACK);
}
void Task11_LCD(void)
{
//初始化内存堆
//lwmem_initialize(0);
delay_ms(500);
fb_cons_clear();//清屏
//while(KEY_SKipTask())
//{
// 颜色充填演示
fb_fillrect(0, 0, 800, 480, cidxRED);
delay_ms(1500);
fb_fillrect(0, 0, 800, 480, cidxYELLOW);
delay_ms(1500);
fb_fillrect(0, 0, 800, 480, cidxBLUE);
delay_ms(1500);
fb_fillrect(0, 0, 800, 480, cidxBLACK);
delay_ms(1500);
// 图片演示
display_pic(50,50,400,400,gImage_img); //显示图片
delay_ms(1500);
//}
}
void Task12_Toush(void)
{
//GT1151_Init();
//GT1151_Test();
}
// 自检任务演示--综合
void TaskDemo_AND(void)
{
// 综合演示模式
while(1)
{
GuiRowText(0, 0,480, FONT_MID,"龙芯1B自检程序");
TaskTextRoll("Task1_LED",0);
TaskTextRoll("0",1);
Task1_LED();
delay_ms(1000);
TaskTextRoll("Task2_KEY",0);
TaskTextRoll("0",1);
Task2_KEY();
delay_ms(1000);
TaskTextRoll("Task3_BEEP",0);
TaskTextRoll("0",1);
Task3_BEEP();
delay_ms(1000);
TaskTextRoll("Task4_UART",0);
TaskTextRoll("0",1);
Task4_UART();
delay_ms(1000);
TaskTextRoll("Task5_FAN_HOT",0);
TaskTextRoll("0",1);
Task5_FAN_HOT();
delay_ms(1000);
TaskTextRoll("Task6_VOICE",0);
TaskTextRoll("0",1);
Task6_VOICE();
delay_ms(1000);
TaskTextRoll("Task7_SMG",0);
TaskTextRoll("0",1);
Task7_SMG();
delay_ms(1000);
TaskTextRoll("Task8_I2C_ADC",0);
TaskTextRoll("0",1);
Task8_I2C_ADC();
delay_ms(1000);
TaskTextRoll("Task9_PWM",0);
TaskTextRoll("0",1);
Task9_PWM();
delay_ms(1000);
TaskTextRoll("Task10_BH1750",0);
TaskTextRoll("0",1);
Task10_BH1750();
delay_ms(1000);
TaskTextRoll("Task11_LCD",0);
TaskTextRoll("0",1);
Task11_LCD();
delay_ms(1000);
//TaskTextRoll("Task12_Toush",0);
//TaskTextRoll("0",1);
//Task12_Toush();
//delay_ms(1000);
break;
}
}
// 自检任务演示--单独
void TaskDemo_ONE(void)
{
int taskNum = 1; // 选择的任务数(1~11)
unsigned char keyNum = 0; // 1.- 2.确定 3.+ 4.退出
// 清光标
fb_fillrect(0, 0, 800, 60, cidxBLACK);
// 任务列表显示
TaskTextRoll("Task1_LED",2);
TaskTextRoll("Task2_KEY",2);
TaskTextRoll("Task3_BEEP",2);
TaskTextRoll("Task4_UART",2);
TaskTextRoll("Task5_FAN_HOT",2);
TaskTextRoll("Task6_VOICE",2);
TaskTextRoll("Task7_SMG",2);
TaskTextRoll("Task8_I2C_ADC",2);
TaskTextRoll("Task9_PWM",2);
TaskTextRoll("Task10_BH1750",2);
TaskTextRoll("Task11_LCD",2);
char* data[10];
// 单独演示模式
while(1)
{
sprintf(data,"%d ",taskNum);
GuiRowText(0, 0 ,40, FONT_LEFT,data);
keyNum = KEY_Scan();
switch(keyNum)
{
case 1: // 减
if(taskNum-1>0)
{
taskNum-=1;
// 清光标
//fb_fillrect(0, 0, 800, 60, cidxBLACK);
// 光标(任务数选择)
//GuiFillRect(0,0+20*(taskNum),20,20+20*(taskNum),cidxWHITE);
}
break;
case 4: // 确定
switch(taskNum)
{
case 1:
Task1_LED();
break;
case 2:
Task2_KEY();
break;
case 3:
Task3_BEEP();
break;
case 4:
Task4_UART();
break;
case 5:
Task5_FAN_HOT();
break;
case 6:
Task6_VOICE();
break;
case 7:
Task7_SMG();
break;
case 8:
Task8_I2C_ADC();
break;
case 9:
Task9_PWM();
break;
case 10:
Task10_BH1750();
break;
case 11:
Task11_LCD();
break;
}
break;
case 3: // 加
if(taskNum+1<12)
{
taskNum+=1;
// 清光标
fb_fillrect(0, 0, 800, 60, cidxBLACK);
// 光标(任务数选择)
//GuiFillRect(0,0+20*(taskNum),20,20+30*(taskNum),cidxWHITE);
}
break;
}
}
}
int DemoMode = 1; // 演示模式 1.综合演示模式 2.单独演示模式
// 自检任务
void TaskDemo(void)
{
unsigned char keyNum = 0; // 健值
// 屏幕显示初始化
fb_open(); //打开LCD显示
delay_ms(500);
fb_cons_clear(); //清屏
defaultFontInit(); /* 字库初始化 */
GuiUpdateDisplayAll(); /* 更新屏幕-清屏 */
// 开机介绍
GuiRowText(0, 240,480, FONT_MID,"龙芯1B自检程序介绍");
GuiRowText(0, 290,480, FONT_LEFT," 任务会按顺序依次演示,大多");
GuiRowText(0, 330,480, FONT_LEFT,"数任务是存在循环演示,可以按S4");
GuiRowText(0, 370,480, FONT_LEFT,"按键跳转到下个任务。现在就可以");
GuiRowText(0, 410,480, FONT_LEFT,"按下S4按键开始自检程序。");
while(KEY_SKipTask());
fb_fillrect(0, 0, 800, 480, cidxBLACK);
delay_ms(1000);
// 演示模式选择
KEY_Init();
GuiRowText(0, 340,480, FONT_MID,"->综合演示模式");
GuiRowText(0, 400,480, FONT_MID," 单独演示模式");
while(KEY_SKipTask())
{
keyNum = KEY_Scan();
switch(keyNum)
{
case 1: // 1.综合演示模式
DemoMode = 1;
GuiRowText(0, 340,480, FONT_MID,"->综合演示模式");
GuiRowText(0, 400,480, FONT_MID," 单独演示模式");
break;
case 2: // 2.单独演示模式
DemoMode = 2;
GuiRowText(0, 340,480, FONT_MID," 综合演示模式");
GuiRowText(0, 400,480, FONT_MID,"->单独演示模式");
break;
}
}
fb_fillrect(0, 0, 800, 480, cidxBLACK);
// 进入模式
switch(DemoMode)
{
case 1:
TaskDemo_AND();
break;
case 2:
TaskDemo_ONE();
break;
}
}
int main(void)
{
printk("\r\nmain() function.\r\n");
ls1x_drv_init(); /* Initialize device drivers */
install_3th_libraries(); /* Install 3th libraies */
// 屏幕显示初始化
fb_open(); //打开LCD显示
delay_ms(500);
fb_cons_clear(); //清屏
defaultFontInit(); /* 字库初始化 */
GuiUpdateDisplayAll(); /* 更新屏幕-清屏 */
KEY_Init();
// 自检程序
TaskDemo();
/*
* 裸机主循环
*/
for (;;)
{
//unsigned int tickcount = get_clock_ticks();
//printk("tick count = %i\r\n", tickcount);
//BH1750_Test();
//delay_ms(500);
}
/*
* Never goto here!
*/
return 0;
}
/*
* @@ End
*/
完整工程链接,希望能帮助到大家!
龙芯1B开发板自检程序
链接:https://pan.baidu.com/s/1dyx5YroQxsvu4-pEHARj3Q 提取码:di6t