Наверное единственный ресурс где всё разжёвано по PIC16.
Скажу сразу – получилось не всё, пробовал погонять в PROTEUS’е, но ШИМ там почему то не запустился.
Прошу прощения – поставил осциллограф и увидел импульсы. Вот только размах импульсов почему то 500 мВ. Цифровой анализатор такие уровни не видит.
Так что всё в порядке, Proteus тоже рулит! ))
Статьи супер!
Вот только было бы вообще классно еслиб была указана конкретная версия компилятора, и какая версия Стандарт или Про. У меня ни один проект в котором используются __delay_ms(xx) так и не скомпилировался…. :((((
Компилятор Hi-tech PICC compiler pro 9.71a. Посмотрите мануал на ваш компилятор по поводу использования в нем этого макроса, либо давайте ваш email и я скину вам свой компилятор.
Огромное спасибо Автору! Как-то давно писал программу для 16ф84 на ассемблере, теперь понадобилось снова, решил на 16ф628 сделать устройство и на Си программу, тем более что опыт программирования на Си под дос был. Не было только разжеванного мануала, как для ассемблера. Тут я нашел все необходимое. И I2C, когда-то освоенные на ассемблере, и требуемый сейчас 1-провод, и ШИМ(в симуляторе MPLAB элментарно запустился, только не сразу, а после переполнения таймера 🙂 ) и много чего полезного. Доступно и понятно(ну кто уже связывался с Си, МК). Спасибо еще раз.
Привет админ! На контроллерах можно всякой интересной всячины творить!
Только не пойму язык, на котором вы программируете. Если на С – впишите название хорошего учебника, заточенного под PIC.
У тебя же копии ответа на коммент на мыло отсылаются? 🙂 Если нет и если не трудно – на почту ответь.
А так благодарю за проявленный интерес к аудитории! 🙂
Язык С, компилятор написан прямо на этой странице вверху.
Про учебник тоже ничего не посоветую, т.к. сам учился по всяким quick starts и по примерам программ с забугорных сайтов, а учебника по pic микроконтроллерам для себя я толкового и не нашел, мне они все показались излишне затянутыми и перегруженными (за исключением небольшого мануала от mikroelektronika).
PS. Для себя я давно понял, что самый быстрый способ научится что-то делать – это подстраиваясь под конкретную задачу искать конкретные статьи и мануалы.
Да , Шпак отдыхает . Спасибо за ваш труд . Я новичок зеленый совсем .
Облазил кучу сайтов , но так как здесь нигде не расписано . Да и исходники много где не выкладывают .
Уважаемый sarge!
С вашей подачи начал изучать Си, многое прояснилось и начало получаться. Но вот столкнулся с одной проблемой. В ходе измерения напряжения с помощью АЦП нужно перемножить два числа, результат заведомо больше 65536. Все это происходит в функции обработки результата оцифровки. Так вот, операция умножения в функции обработки вызывает стандартную функцию умножения из файла wmul.c. А эта функция умножения возвращает значение типа unsigned int, естественно, усеченное. Явное указание типа перед произведением ничего не меняет, все равно вызывается функция из файла wmul.c. А вот если разместить операцию умножения чисел не в функции обработки, а непосредственно в main(), то происходит вызов функции умножения уже из файла lmul.c, которая возвращает значение типа unsigned long. Но ведь неудобно все вычисления располагать непосредственно в теле main(), для того и была придумана система функций. Смена компилятора с HI_TECH_Software v9.71 на xc8 ничего не дала, там аналогичные процессы. Можно, конечно, скопировать текст функции умножения нужного формата в отдельную функцию, пристегнуть ее к проекту и везде вместо умножения делать ее вызов. Можно, работает, но крайне неудобно.
Почему так своевольничают компиляторы? Может, я нарушаю какие-то правила? В ассемблере подобных “фокусов” не встречал. Текст программы прилагаю.
//==============================================================
#include
unsigned int Uref=500; long int Uout; // переменные для АЦП
long int convDigToU(unsigned int Dig, unsigned int U1); // ф-я преобразования (фрагмент)
unsigned long multipl(unsigned long mult1,unsigned long mult2);
// unsigned int – до 65535; long int – до 4 294 967 295
void
main(void)
{
long int k1,k2; // до 4294967295
Uout = 0;
k2 = 132; // начальное значение
k1=0;
Uout=k2*500; // здесь вызывается функция умножения unsigned long __lmul()
// из файла lmul.c, она возвращает результат типа long.
// результат умножения правильный.
k1=k2*500;
Uout=0; k1=0; // сброс
Uout = convDigToU(k2,Uref); // при k2=132 результат неверный
Uout = multipl(k2,Uref); // результат правильный.
}
// =============================================================
// функция обработки (фрагмент умножения двух чисел)
long int
convDigToU(unsigned int Dig, unsigned int U1)
{
long int sd1,sd2;
sd1 = (long int)(Dig*U1); // тут вызывается ф-я unsigned int __wmul() из wmul.c
// ее максимальное возвращаемое значение 65535, а результат произведения
// заведомо больше и функцией урезается. Принудительное назначение типа
// (long int) не срабатывает.
sd1 = multipl(Dig,U1); // результат правильный
return sd1;
}
// =============================================================
// копия стандартной функции умножения из lmul.c
unsigned long
multipl(unsigned long multiplier, unsigned long multiplicand)
{
unsigned long product = 0;
Я так глубоко конкретно в этой области никогда не копал, но то, что вы показываете у меня противоречий не вызывает. Функция оперирует элементами лонг инт, и насколько я понимаю ваши данные урежутся еще до операции в этот же инт.
Вы написали свою функцию, которая работает – замечательно, хотите чтобы она была отдельным файлом – вынесите ее в какойнить mymath.c mymath.h, лично я тут никаких неудобств не вижу.
А вопросы по компилятору – точно не ко мне, я просто любитель и не занимаюсь программмрованием профессионально. Так что здесь я в такой же позиции как и вы 😀
Наверное я слишком мудрено сформулировал свою проблему. Попробую попроще. Есть два числа в виде переменных типа int a=500, b=132; Нужно получить их произведение, это уже тип long int c;
Нужно c = a * b. Если эту операцию выполнять в ф-ии main(), то результат будет 66000. А если то же самое произведение выполнить в функции, аргументы которой int (и a и b не превышают), но которая должна возвращать тип long int (и это объявлено), результат будет 464, т.е. урезан до int. И принудительное приведение типов не помогает. А вот если аргументы функции объявить как long, ее результат будет правильным.
Почему в первом случае функция понижает результат, хотя ее возвращаемое значение объявлено как long int?
Да, у вас было слишком много дополнительной информации, которая на мой взгляд только сбивает с толку – АЦП, конверсии – все это не важные дополнения, я люблю простые вещи, особенно при дебаге.
Дальше, вы пытаетесь вытянуть у меня знания, которых я в принципе не особо имею, но попытаюсь помочь.
Действительно, я попробовал набросать код с умножением в мейне и в функции, но у меня везде его урезало до 464 (pic16f628a, hi-tech picc c compiler 9.71), но если сделать приведение типов не так как у вас, а для каждой переменной, то все замечательно отрабатывает:
#include <stdio.h>;
#include <htc.h>;
#define _XTAL_FREQ 4000000
#include "usart.h";
__CONFIG(LVPDIS & WDTDIS & MCLREN & UNPROTECT & HS);
int a=500, b=132;
long int c_fun;
void PrintMultipl(int ain, int bin);
void main(void){
TRISB4 = 0; TRISB6 = 0; TRISB7 = 0; TRISB5 = 0;
init_comms(); // set up the USART - settings defined in usart.h
printf("Starting...\r\n");
printf("Hello, World!\n");
long int c = (long int)a*(long int)b;
printf("From main: \r\n");
printf("%d",c);
printf("\r\n");
PrintMultipl(a, b);
while(1){};
}
void PrintMultipl(int ain, int bin)
{
c_fun = (long int)ain * (long int)bin;
printf("From function: \r\n");
printf("%d",c_fun);
printf("\r\n");
}
Результат:
Обратите внимание, что переменная здесь имеет правильную величину, но в printf она усекается до int.
P.S. И не спрашивайте почему приведение типов надо делать так, я не смогу дать теоретического обоснования 🙂
Уважаемый sarge! Большое спасибо за ответ.
Я еще новичок в Си, читаю книжки и верю всему, что написано. А для PIC16 по ряду вопросов, видимо, есть свои оговорки. В частности, в hi-tech picc c compiler 9.71 аж четыре функции умножения: для unsigned char, для unsigned int, для unsigned short long и для unsigned long (соотв. 1, 2, 3 и 4 байтные). Компилятор анализирует входные аргументы и вызывает соответствующую функцию. И для типа int результат будет только int, не выше. Потому что будет вызван двухбайтный вариант (wmul.c), который возвращает значение int. И заставить ее возвращать long никак не получится. А значение long может вернуть только функция из lmul.c. А чтобы вызвать ее, аргументы д.б. не int, а long, это обязательно. Либо, как вариант – скопировать тело в свою функцию, где сделать нужные определения. Хороший урок, очень полезный. Еще раз спасибо!
В процессе изучения вопроса столкнулся с типом “unsigned short long” – ни в одном справочнике его не нашел, поиск в Гугле тоже ничего не дал. Он используется в файле tmul.c и в массе других. Как оказалось, это 24-битный формат данных, нечто среднее между int и long. Как я понимаю, очередная особенность от PIC16.
Наверное единственный ресурс где всё разжёвано по PIC16.
Скажу сразу – получилось не всё, пробовал погонять в PROTEUS’е, но ШИМ там почему то не запустился.
Я протеусу не сильно доверяю, лучше сразу на железе проверять.
Прошу прощения – поставил осциллограф и увидел импульсы. Вот только размах импульсов почему то 500 мВ. Цифровой анализатор такие уровни не видит.
Так что всё в порядке, Proteus тоже рулит! ))
Ну правильно, потому что у вас скорее всего щупы с делителем 10:1. Таким образом реальная амплитуда равна 500мВ*10 = 5 В.
у меня все получилось,Саржу огромный респект и законное место в истории!
Статьи супер!
Вот только было бы вообще классно еслиб была указана конкретная версия компилятора, и какая версия Стандарт или Про. У меня ни один проект в котором используются __delay_ms(xx) так и не скомпилировался…. :((((
Компилятор Hi-tech PICC compiler pro 9.71a. Посмотрите мануал на ваш компилятор по поводу использования в нем этого макроса, либо давайте ваш email и я скину вам свой компилятор.
Огромное спасибо Автору! Как-то давно писал программу для 16ф84 на ассемблере, теперь понадобилось снова, решил на 16ф628 сделать устройство и на Си программу, тем более что опыт программирования на Си под дос был. Не было только разжеванного мануала, как для ассемблера. Тут я нашел все необходимое. И I2C, когда-то освоенные на ассемблере, и требуемый сейчас 1-провод, и ШИМ(в симуляторе MPLAB элментарно запустился, только не сразу, а после переполнения таймера 🙂 ) и много чего полезного. Доступно и понятно(ну кто уже связывался с Си, МК). Спасибо еще раз.
Спасибо за отзыв! 🙂
Пишите еще , очень полезно. Спасибо.
Буду стараться 🙂
тестовый коммент
Привет админ! На контроллерах можно всякой интересной всячины творить!
Только не пойму язык, на котором вы программируете. Если на С – впишите название хорошего учебника, заточенного под PIC.
У тебя же копии ответа на коммент на мыло отсылаются? 🙂 Если нет и если не трудно – на почту ответь.
А так благодарю за проявленный интерес к аудитории! 🙂
Язык С, компилятор написан прямо на этой странице вверху.
Про учебник тоже ничего не посоветую, т.к. сам учился по всяким quick starts и по примерам программ с забугорных сайтов, а учебника по pic микроконтроллерам для себя я толкового и не нашел, мне они все показались излишне затянутыми и перегруженными (за исключением небольшого мануала от mikroelektronika).
PS. Для себя я давно понял, что самый быстрый способ научится что-то делать – это подстраиваясь под конкретную задачу искать конкретные статьи и мануалы.
Эксперимент 24 исчез, если не ошибаюсь- датчик влажности. Сайт хороший, продолжайте. Успехов.
Спасибо, я и не заметил, что он отсюда пропал. Поправил 🙂
Написать бы вам книгу прямиком со всеми опытами, получится наглядней чем у Шпака. И содержание ооочень емкое и полезное.
В книгу видео не вставишь, а это иногда бывает очень полезно 🙂
Да и ресурсы/возможности не те.
Да , Шпак отдыхает . Спасибо за ваш труд . Я новичок зеленый совсем .
Облазил кучу сайтов , но так как здесь нигде не расписано . Да и исходники много где не выкладывают .
Спасибо за отзыв!
Уважаемый sarge!
С вашей подачи начал изучать Си, многое прояснилось и начало получаться. Но вот столкнулся с одной проблемой. В ходе измерения напряжения с помощью АЦП нужно перемножить два числа, результат заведомо больше 65536. Все это происходит в функции обработки результата оцифровки. Так вот, операция умножения в функции обработки вызывает стандартную функцию умножения из файла wmul.c. А эта функция умножения возвращает значение типа unsigned int, естественно, усеченное. Явное указание типа перед произведением ничего не меняет, все равно вызывается функция из файла wmul.c. А вот если разместить операцию умножения чисел не в функции обработки, а непосредственно в main(), то происходит вызов функции умножения уже из файла lmul.c, которая возвращает значение типа unsigned long. Но ведь неудобно все вычисления располагать непосредственно в теле main(), для того и была придумана система функций. Смена компилятора с HI_TECH_Software v9.71 на xc8 ничего не дала, там аналогичные процессы. Можно, конечно, скопировать текст функции умножения нужного формата в отдельную функцию, пристегнуть ее к проекту и везде вместо умножения делать ее вызов. Можно, работает, но крайне неудобно.
Почему так своевольничают компиляторы? Может, я нарушаю какие-то правила? В ассемблере подобных “фокусов” не встречал. Текст программы прилагаю.
//==============================================================
#include
unsigned int Uref=500; long int Uout; // переменные для АЦП
long int convDigToU(unsigned int Dig, unsigned int U1); // ф-я преобразования (фрагмент)
unsigned long multipl(unsigned long mult1,unsigned long mult2);
// unsigned int – до 65535; long int – до 4 294 967 295
void
main(void)
{
long int k1,k2; // до 4294967295
Uout = 0;
k2 = 132; // начальное значение
k1=0;
Uout=k2*500; // здесь вызывается функция умножения unsigned long __lmul()
// из файла lmul.c, она возвращает результат типа long.
// результат умножения правильный.
k1=k2*500;
Uout=0; k1=0; // сброс
Uout = convDigToU(k2,Uref); // при k2=132 результат неверный
Uout = multipl(k2,Uref); // результат правильный.
}
// =============================================================
// функция обработки (фрагмент умножения двух чисел)
long int
convDigToU(unsigned int Dig, unsigned int U1)
{
long int sd1,sd2;
sd1 = (long int)(Dig*U1); // тут вызывается ф-я unsigned int __wmul() из wmul.c
// ее максимальное возвращаемое значение 65535, а результат произведения
// заведомо больше и функцией урезается. Принудительное назначение типа
// (long int) не срабатывает.
sd1 = multipl(Dig,U1); // результат правильный
return sd1;
}
// =============================================================
// копия стандартной функции умножения из lmul.c
unsigned long
multipl(unsigned long multiplier, unsigned long multiplicand)
{
unsigned long product = 0;
do {
if(multiplier & 1)
product += multiplicand;
multiplicand <>= 1;
} while(multiplier != 0);
return product;
}
Добрый день,
Я так глубоко конкретно в этой области никогда не копал, но то, что вы показываете у меня противоречий не вызывает. Функция оперирует элементами лонг инт, и насколько я понимаю ваши данные урежутся еще до операции в этот же инт.
Вы написали свою функцию, которая работает – замечательно, хотите чтобы она была отдельным файлом – вынесите ее в какойнить mymath.c mymath.h, лично я тут никаких неудобств не вижу.
А вопросы по компилятору – точно не ко мне, я просто любитель и не занимаюсь программмрованием профессионально. Так что здесь я в такой же позиции как и вы 😀
Наверное я слишком мудрено сформулировал свою проблему. Попробую попроще. Есть два числа в виде переменных типа int a=500, b=132; Нужно получить их произведение, это уже тип long int c;
Нужно c = a * b. Если эту операцию выполнять в ф-ии main(), то результат будет 66000. А если то же самое произведение выполнить в функции, аргументы которой int (и a и b не превышают), но которая должна возвращать тип long int (и это объявлено), результат будет 464, т.е. урезан до int. И принудительное приведение типов не помогает. А вот если аргументы функции объявить как long, ее результат будет правильным.
Почему в первом случае функция понижает результат, хотя ее возвращаемое значение объявлено как long int?
Да, у вас было слишком много дополнительной информации, которая на мой взгляд только сбивает с толку – АЦП, конверсии – все это не важные дополнения, я люблю простые вещи, особенно при дебаге.
Дальше, вы пытаетесь вытянуть у меня знания, которых я в принципе не особо имею, но попытаюсь помочь.
Действительно, я попробовал набросать код с умножением в мейне и в функции, но у меня везде его урезало до 464 (pic16f628a, hi-tech picc c compiler 9.71), но если сделать приведение типов не так как у вас, а для каждой переменной, то все замечательно отрабатывает:
Результат:

Обратите внимание, что переменная здесь имеет правильную величину, но в printf она усекается до int.
P.S. И не спрашивайте почему приведение типов надо делать так, я не смогу дать теоретического обоснования 🙂
Ну и вот тут вроде объясняют почему нельзя перемножить два 16 битных числа в одно 32 битное:
http://www.microchip.com/forums/m551563.aspx
Уважаемый sarge! Большое спасибо за ответ.
Я еще новичок в Си, читаю книжки и верю всему, что написано. А для PIC16 по ряду вопросов, видимо, есть свои оговорки. В частности, в hi-tech picc c compiler 9.71 аж четыре функции умножения: для unsigned char, для unsigned int, для unsigned short long и для unsigned long (соотв. 1, 2, 3 и 4 байтные). Компилятор анализирует входные аргументы и вызывает соответствующую функцию. И для типа int результат будет только int, не выше. Потому что будет вызван двухбайтный вариант (wmul.c), который возвращает значение int. И заставить ее возвращать long никак не получится. А значение long может вернуть только функция из lmul.c. А чтобы вызвать ее, аргументы д.б. не int, а long, это обязательно. Либо, как вариант – скопировать тело в свою функцию, где сделать нужные определения. Хороший урок, очень полезный. Еще раз спасибо!
В процессе изучения вопроса столкнулся с типом “unsigned short long” – ни в одном справочнике его не нашел, поиск в Гугле тоже ничего не дал. Он используется в файле tmul.c и в массе других. Как оказалось, это 24-битный формат данных, нечто среднее между int и long. Как я понимаю, очередная особенность от PIC16.
Да, возможно очередная особенность…
Если мой пример был полезен, рад был помочь, чем смог 🙂
Спасибо за энкодер – все отлично рассказано.
А есть ли модель мотора с энкодером для протеуса ?
Пожалуйста.
Модели мотора с энкодером я не делал, так что нет.